如何避免NotSupportedException?

时间:2019-02-25 13:46:06

标签: c# asp.net entity-framework linq

我改了这篇文章:The entity cannot be constructed in a LINQ to Entities query,但猜想它与我的问题并不完全相关。

我有此代码:

public class Class1
{
        public string Prop1 { get; set; }
        public string Prop2 { get; set; }
        public string Prop3 { get; set; }
}

[Table("Class2")]
public class Class2
{
        [Key]
        [Column("Prop1")]
        public string Prop1 { get; set; }

        [Column("Prop2")]
        public string Prop2 { get; set; }

        [Column("Prop3")]
        public string Prop3 { get; set; }
}

在我想使用这些方法的地方进行方法编辑:

using (var data = new Context())
{
    var config = data.Class2.FirstOrDefault(c => c.Prop1.Contains(some_string));
    if (config != null)
    {
        config.Prop1 = class1_instance.Prop1;
        config.Prop2 = class1_instance.Prop2;
        config.Prop3 = class1_instance.Prop3;
    }
    data.Entry(config).State = EntityState.Modified;
    data.SaveChanges();
}

所以我想要得到的是简化编辑,而不是一个一个地分配每个属性,而是要编写类似config = class1_instance;

所以我从Class1继承了Class2,但得到

  

System.NotSupportedException(不能在Linq to Entities查询中构造实体或复杂类型“ Class1”)。

我该如何处理?

2 个答案:

答案 0 :(得分:3)

不要从实体类继承DTO类,因为EF6会将DTO视为参与某些受支持的数据库继承策略的实体。

相反,请使用DbPropertyValues的{​​{1}}属性返回的CurrentValues的{​​{3}}:

  

通过从给定对象中读取值来设置此字典的值。给定的对象可以是任何类型。名称上与字典中的属性名称匹配并且可以读取的对象上的任何属性都将被读取。其他属性将被忽略。例如,这允许从简单的数据传输对象(DTO)复制属性。

例如

DbEntityEntry

请注意,目标实体已由db上下文附加(跟踪),因此无需将输入状态设置为Class1 source = ...; var target = data.Class2.FirstOrDefault(...); if (target != null) { data.Entry(target).CurrentValues.SetValues(source); data.SaveChanges(); }

答案 1 :(得分:0)

现在,Class1和Class2具有相同的属性。这是故意的还是偶然的?可能是Class2的未来版本具有Class1以外的属性吗?

  

在实体框架中,DbSet<...>代表数据库的表。 DbSet中的类表示表中的一行。表的列是该类的非虚拟属性。虚拟属性表示表之间的关系(一对多,多对多...)

Class2代表数据库表。如果假定Class1等于Class2,那么Class1的原因是什么。如果只是现在这样,而在将来的版本中它们可能会有所不同,则必须一一复制属性。

void UpdateValue(string someString, Class1 value)
{
    using (var dbContext = new DbContext())
    {
        Class2 fetchedData = dbContext.Class2.Where(...).FirstOrDefault();
        if (fetchedData != null)
        {   // data exists. Update the properties
            fetchedData.Prop1 = value.Prop1,
            fetchedData.Prop2 = value.Prop2,
            fetchedData.Prop3 = value.Prop3,

            // future version of Class2 may have properties that are not updated
            // no need to set state to modified. Entity Framework will detect the changes
            dbContext.SaveChanges();
        }
    }
}

如果您现在和将来都可以肯定每个Class2Class1的特殊类型,则可以考虑从Class1派生Class2:

class Class2 : Class1
{
    public int Id {get; set;}
    ... // properties that are in Class2, but not in Class1
}

这意味着Class1的每个非虚拟属性都由Classes2的表中的一列表示。

即使您进行派生,派生也无济于事,您必须一一复制属性。如果您需要多次执行此操作,请考虑创建一个为您复制正确值的函数。