简体   繁体   中英

system.InvalidOperationException in entityframework

I have a problem when I update a line with a foreign key. The principle idea is to update a row in the database with a generic method but I have an exception when I save modification in the data base so I try to make the state of entity os modified but not the worker.

else if (ModeButtonVMCaracteristiquesType == ModeButtonVMCaracteristiqueType.EDITIONCaracteristiqueTypeItem)
{
    int idCaracteristiqueSelected = Convert.ToInt32(CaracteristiqueSelected.idCharacteristicItem);

    var LineModified = (from x in ImItemsModel.imtypeitems select x.imcharacteristicsitems).ToList();
    LineModified.ForEach(p => ImItemsModel.Entry(p).State = System.Data.Entity.EntityState.Modified);
    var UpdateCaracteristicTypeItem = StaticGenericUpdate.UpadateRowInModel<imcharacteristicsitem>(ImItemsModel, "idCharacteristicItem", idCaracteristiqueSelected, "fk_idTypeItemIMCaracteristicsItems", fk_value, propertiesForModel, propertiesForView, this);

    ImItemsModel.SaveChanges();

So I have two models:

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; }
}

and:

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; }
} 

and the generic method is:

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;   
}

EDIT : so i realise that the probleme is the entity framework can't save because my table imtypeitems have a collection of caractéristique

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

so i must delet the row that i wish update it from this table and after that i will save so i can't delet the row of collection i try like this :

  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); 

just a ps : i am not a expert in entity framework :(

The most likely cause for the FK null exception is that the FK entity property is processed/set in the foreach loop after the FK_ID property. So even if you change the FK_ID IsModified value to false , you're most likely later setting the imtypeitem property to null.

Also you are changing all model properties based on view properties; so if there's no particular view property you'll be setting the model property to null. This is seldom the thing you want to be doing in this scenario. Usually you want to change just the corresponding view properties and leave the other model properties unchanged.

So the foreach part of your generic method should look like this:

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

If you have certain properties that are part of view properties but you don't want them to be updated you can just skip them (using your Nameid and NameFk_key ):

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

So the final form of the generic method might look something like this:

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;   
}

There's also a variation possible where you do a foreach on the propertiesView ; also the parameters for the method can be adjusted.

On a sidenote: I'm not sure if

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

does something useful, or if it does anything. The p in lambda is an ICollection of enity types and not a separate DB context entity. Not to mention that you want to set Modified state for ALL entities of type imcharacteristicsitem . Maybe you can explain the reason for this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM