Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • David Peck 687 posts 1863 karma points c-trib
    Mar 14, 2023 @ 10:34
    David Peck
    0

    Updating a property with no setter rather than replacing it (EF Core)

    I'm using EF Core. One of my properties on my Resource entity is like this:

    public virtual ICollection<ResourceType> ResourceTypes { get; } = new List<ResourceType>();
    

    I've set ValueMappers, data types, and configurator to allow me to set ResourceTypes correctly in the UI. However the property doesn't get updated because it has no setter. What I want Konstrukt to do is to update the ICollection and not replace it. I see no way to achieve this other than to have a fake duplicate ResourceTypes property and using an event/custom repo to move sync the two properties. If feels hacky.

    Is there no other way to achieve this? Ideally the original property would be provided in the ValueMapper and I could then update this rather than return a new object.

  • David Peck 687 posts 1863 karma points c-trib
    Mar 14, 2023 @ 13:51
    David Peck
    100

    If anyone else has this issue, then please know that my solution was to create a new model for Konstrukt (in my case):

    // Must be a super class of Resource for the ReplaceVisitor to work
    public class ResourceModel : Resource
    {
        public readonly Resource Resource;
    
        public ResourceModel (Resource resource)
        {
            // Copy properties
            Id = resource.Id;
            Name = resource.Name;
        }
    
        // a new property that then allows for setting
        public new ICollection<ResourceType> ResourceTypes {
            get => Resource.ResourceTypes;
            set => UpdateCollectionContents(Resource.ResourceTypes, value);
        }
    
        public static void UpdateCollectionContents<TEntity> (ICollection<TEntity> collection, IEnumerable<TEntity> newContents)
        {
            collection.Clear();
            foreach (var entity in newContents)
            {
                collection.Add(entity);
            }
        }
    }
    

    However that then requires that you have a custom repository (which I already did). Unfortunately all the Expressions for where and order by are then refer to your new model rather than your entity. So you need to do some magic to change the input type of your expression:

    public static Expression<Func<Resource, TResult>> ToEntityExpression<TResult> (Expression<Func<ResourceModel, TResult>> expression)
    {
        var resourceParam = Expression.Parameter(typeof(Resource));
        return Expression.Lambda<Func<Resource, TResult>>(
            new ReplaceVisitor(expression.Parameters[0], resourceParam).Visit(expression.Body)!,
            resourceParam);
    }
    
    
    internal class ReplaceVisitor : ExpressionVisitor
    {
        private readonly Expression _from, _to;
        public ReplaceVisitor (Expression from, Expression to)
        {
            this._from = from;
            this._to = to;
        }
        public override Expression? Visit (Expression? node)
        {
            return node == _from ? _to : base.Visit(node);
        }
    }
    
  • David Peck 687 posts 1863 karma points c-trib
    Mar 22, 2023 @ 11:21
    David Peck
    0

    I'm being prompted for a solution by the forum. I'm going to mark my post above as such, but it would be ideal if in the future Konstrukt could update ICollection properties rather than attempt to overwrite it.

Please Sign in or register to post replies

Write your reply to:

Draft