entityframework中的system.InvalidOperationException

时间:2017-09-17 18:04:46

标签: c# entity-framework

使用外键更新一行时遇到问题。原理思想是使用泛型方法更新数据库中的行,但是当我在数据库中保存修改时我有一个例外,因此我尝试修改实体的状态,但不修改工作者。

public partial class imcharacteristicsitem
{
    public imcharacteristicsitem()
    {
        this.imvaluesofitemscaracteristics = new HashSet<imvaluesofitemscaracteristic>();
    }

    public int idCharacteristicItem { get; set; }
    public string characteristicItem { get; set; }
    public string unitCaracteristicItem { get; set; }
    public int fk_idTypeItemIMCaracteristicsItems { get; set; }
    public byte[] typeValueCaracteristicItem { get; set; }

    public virtual ICollection<imvaluesofitemscaracteristic> imvaluesofitemscaracteristics { get; set; }
    public virtual imtypeitems imtypeitem { get; set; }
}

所以我有两个模特:

public partial class imtypeitems
{
    public imtypeitems()
    {
        this.imcharacteristicsitems = new HashSet<imcharacteristicsitem>();
        this.imitems = new HashSet<imitem>();
    }

    public int idTypeItem { get; set; }
    public string DesignationTypeItem { get; set; }
    public byte[] SymbolTypeItem { get; set; }
    public Nullable<int> MaxNumberConnectionsTypeItem { get; set; }

    public virtual ICollection<imcharacteristicsitem> imcharacteristicsitems { get; set; }
    public virtual ICollection<imitem> imitems { get; set; }
} 

public static T UpadateRowInModel<T>(DbContext Model, string NameiD, int IdSelected, string NameFk_key  ,int fk_key, IList<PropertyInfo> propertiesModel, IList<PropertyInfo> propertiesView, VMCaracteristicType vm) where T : class
{
    T item = Model.Set<T>().Find(IdSelected);

    foreach (var property in propertiesModel)
    {
        if (propertiesView.Count != 0)
        {
            property.SetValue(item, propertiesView.FirstOrDefault(elem => elem.Name.Equals(property.Name)) == null ? null :
            propertiesView.FirstOrDefault(elem => elem.Name.Equals(property.Name)).GetValue(vm));
        }
        if (property.Name == NameiD)
        {
            property.SetValue(item, IdSelected);
        }
        if (property.Name == NameFk_key)
        {
            property.SetValue(item, null);
            Model.Entry(item).Property(NameFk_key).IsModified = false;
        }
    }

    return item;   
}

,通用方法是:

  public virtual ICollection<imcharacteristicsitem> imcharacteristicsitems { get; set; }

编辑: 所以我意识到问题是实体框架无法保存,因为我的表imtypeitems有一个caractéristique的集合

  var RowBeforupdate = ImItemsModel.imcharacteristicsitems.Include("imtypeitem").Single(row => row.idCharacteristicItem == idCaracteristiqueSelected);
                var UpdateCaracteristicTypeItem = StaticGenericUpdate.UpadateRowInModel<imcharacteristicsitem>(ImItemsModel, "idCharacteristicItem", idCaracteristiqueSelected, "fk_idTypeItemIMCaracteristicsItems", fk_value, propertiesForModel, propertiesForView, this);
                ImItemsModel.Entry(RowBeforupdate).CurrentValues.SetValues(UpdateCaracteristicTypeItem); 

所以我必须删除我希望从此表更新它的行,之后我将保存,所以我不能删除集合的行我尝试这样:

{{1}}

只是一个ps:我不是实体框架的专家:(

1 个答案:

答案 0 :(得分:0)

FK null异常的最可能原因是在FK_ID属性之后的foreach循环中处理/设置FK实体属性。因此,即使您将FK_ID IsModified值更改为false,您最有可能在以后将imtypeitem属性设置为null。

您还要根据视图属性更改所有模型属性;因此,如果没有特定的视图属性,您将设置模型属性为null。在这种情况下,这很少是您想要做的事情。通常,您只想更改相应的视图属性,并保持其他模型属性不变。

因此,泛型方法的foreach部分应如下所示:

if (propertiesView.FirstOrDefault(elem => elem.Name.Equals(property.Name)) != null)
{
    property.SetValue(item, propertiesView.First(elem => elem.Name.Equals(property.Name)).GetValue(vm));
}

如果某些属性属于视图属性但您不希望更新它们,则可以跳过它们(使用NameidNameFk_key):

if(property.Name == NameiD || property.Name == NameFk_key)
    continue;

因此泛型方法的最终形式可能如下所示:

public static T UpadateRowInModel<T>(DbContext Model, string NameiD, int IdSelected, string NameFk_key  ,int fk_key, IList<PropertyInfo> propertiesModel, IList<PropertyInfo> propertiesView, VMCaracteristicType vm) where T : class
{
    T item = Model.Set<T>().Find(IdSelected);

    foreach (var property in propertiesModel)
    {
        if(property.Name == NameiD || property.Name == NameFk_key)
            continue;

        var viewP = propertiesView.FirstOrDefault(elem => elem.Name.Equals(property.Name));
        if (viewP != null)
        {
            property.SetValue(item, viewP.GetValue(vm));
        }            
    }

    return item;   
}

foreach上执行propertiesView的情况下,您也可以进行变更;也可以调整方法的参数。

旁注:我不确定是否

var LineModified = (from x in ImItemsModel.imtypeitems select x.imcharacteristicsitems).ToList();
LineModified.ForEach(p => ImItemsModel.Entry(p).State = System.Data.Entity.EntityState.Modified);

做一些有用的事情,或者它做了什么。 lambda中的p是enity类型的ICollection,而不是单独的DB上下文实体。更不用说您想为Modified类型的所有实体设置imcharacteristicsitem状态。也许你可以解释一下这个原因。