在实体框架中干净地更新层次结构 [英] Cleanly updating a hierarchy in Entity Framework

查看:76
本文介绍了在实体框架中干净地更新层次结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在提交StoredProcedureReport的表单,其中有很多StoredProcedureParameters. Create可以正常工作,但是尝试进行更新使我问微软是否可以认真对待.

I'm submitting a form for a StoredProcedureReport, which has many StoredProcedureParameters. Create works fine, but trying to update has left me asking whether or not Microsoft can seriously be serious.

我来自Rails的背景,@report.update_attributes(params[:report])会确切地知道如何处理在其中找到的任何关联数据.据我所知,.NET的等效项是TryUpdateModel,它看起来很有希望.首先.所以我尝试了一些这样的参数

I come from a Rails background where @report.update_attributes(params[:report]) will know exactly what to do with whatever association data it finds within. From what I can tell, the .NET equivalent of this is TryUpdateModel, which looked promising. At first. So I tried it with some params like this

IDGUID:d70008a5-a1a3-03d2-7baa-e39c5044ad41
StoredProcedureName:GetUsers
Name:search again UPDATED
StoredProcedureReportParameters[0].IDGUID:d70008a5-aba3-7560-a6ef-30a5524fac72
StoredProcedureReportParameters[0].StoredProcedureReportID:d70008a5-a1a3-03d2-7baa-e39c5044ad41
StoredProcedureReportParameters[0].Name:RowsPerPage
StoredProcedureReportParameters[0].Label:rows
StoredProcedureReportParameters[0].StoredProcedureReportParameterDataTypeID:a50008a5-2755-54c0-b052-865abf459f7f
StoredProcedureReportParameters[0].StoredProcedureReportParameterInputTypeID:a50008a5-2955-a593-d00f-00cd4543babf
StoredProcedureReportParameters[0].DefaultValue:10
StoredProcedureReportParameters[0].AllowMultiple:false
StoredProcedureReportParameters[0].Hidden:false
StoredProcedureReportParameters[1].IDGUID:d70008a5-a7a3-e35e-28b6-36dd9e448ee5
StoredProcedureReportParameters[1].StoredProcedureReportID:d70008a5-a1a3-03d2-7baa-e39c5044ad41
StoredProcedureReportParameters[1].Name:PageNumber
StoredProcedureReportParameters[1].Label:page was MODIFIEIIEIEIED!!!
StoredProcedureReportParameters[1].StoredProcedureReportParameterDataTypeID:a50008a5-2755-54c0-b052-865abf459f7f
StoredProcedureReportParameters[1].StoredProcedureReportParameterInputTypeID:a50008a5-2955-a593-d00f-00cd4543babf
StoredProcedureReportParameters[1].DefaultValue:1
StoredProcedureReportParameters[1].AllowMultiple:false
StoredProcedureReportParameters[1].Hidden:false

我假设在设置了所有主键和外键的情况下,EF会在执行此操作时知道如何更新StoredProcedureReportParameter对象:

I assumed that with all the primary and foreign keys set, EF would know how to update the StoredProcedureReportParameter objects when I do this:

var report = context.StoredProcedureReports.FirstOrDefault(r => r.IDGUID == reportID);

if (report != null)
{
    succeeded = TryUpdateModel(report);
    context.SaveChanges();
}

现在,如果我在context.SaveChanges()上放置一个断点,则我的report对象及其关联的StoredProcedureReportParameters看起来就像我期望的那样.设置外键和主键,所有值都检出.但是SaveChanges会引发此错误:

Now, if I place a breakpoint on context.SaveChanges(), my report object and its associated StoredProcedureReportParameters look just like I'd expect them to. The foreign and primary keys are set, ALL the values check out. But SaveChanges raises this error:

操作失败:由于一个或多个外键属性不可为空,因此无法更改该关系.对关系进行更改时,相关的外键属性将设置为空值.如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象.

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

此消息中的建议之一是,我应该为外键属性分配一个非空值,但是正如我所说的,StoredProcedureReportID 具有在两个StoredProcedureReportParameter上都正确对象.

One of the suggestions in this message is that I should assign the foreign-key property a non-null value, but as I stated, StoredProcedureReportID has the correct value on both StoredProcedureReportParameter objects.

我读过的其他有关Update操作的文章遍历关联并将它们附加到上下文中.这真的是我坚持要做的吗? EF真的那么密集吗?我希望有一个.NET专业人士向我展示一下.有 比这更简单的方法.

Other posts I've read that deal with Update operations loop over associations and attach them to the context. Is this really what I'm stuck doing? Is EF really that dense? I'm hoping for a .NET pro to show me the light here. There has to be an easier way than that.

推荐答案

这并不难.使用EF的主要方法有两种:附加实体和分离实体.

It is not that hard. There are 2 main ways to work using EF: Attached entities and Detached entities.

假设我们有2个实体:

public class Foo
{
     public int FooId { get; set; }

     public string Description { get; set; }

     public ICollection<Bar> Bars { get; set; }
 }

public class Bar
{
    public int BarId { get; set; }

    public string Description { get; set; }
}

插入

var foo = new Foo()
{
    FooId = 1,
    Description = "as",
    Bars = new List<Bar>()
    {
        new Bar
        {
            BarId = 1,
            Description = "as"
        },
        new Bar
        {
            BarId = 2,
            Description = "as"
        },
        new Bar
        {
            BarId = 2,
            Description = "as"
        }
    }
};

ctx.Foos.Add(foo);
ctx.SaveChanges();

在上面的示例中,EF将识别新项目,并将其全部插入.

In the above example, EF will recognize the new items, and will insert all of them.

更新(已附加)

var foo = ctx.Foos.Include("Bars").Where(i => i.FooId == 1).FirstOrDefault();
foreach (var bar in foo.Bars)
{
    bar.Description = "changed";
}

ctx.SaveChanges();

在这里,我们从上下文中加载了foo及其栏.它们已经附加到上下文中.因此,我们要做的就是更改值并调用SaveChanges().一切都会正常.

Here we loaded foo and its bars from the context. They are already attached to the context. So, all we need to do is change the values and call SaveChanges(). Everything will work fine.

更新(已删除)

var foo = new Foo
{
    FooId = 1,
    Description = "changed3",
    Bars = new List<Bar>
    {
        new Bar
        {
            BarId = 1,
            Description = "changed3"
        },
        new Bar
        {
            BarId = 2,
            Description = "changed3"
        }
    }
};

ctx.Entry(foo).State = EntityState.Modified;

foreach (var bar in foo.Bars)
{
    ctx.Entry(bar).State = EntityState.Modified;
}

ctx.SaveChanges();

在这里,我们正在处理数据库中已经存在的项目.但是,它们不是从EF加载的(未连接). EF对他们一无所知.我们需要手动附加所有这些文件,并告诉EF它们已被修改.

Here, we are working with items which already exists in database. However, they were not loaded from EF (they are not attached). EF knows nothing about them. We need to attached all of them manually and tell EF that they are modified.

删除(已附着)

var foo = ctx.Foos.Include("Bars").Where(i => i.FooId == 1).FirstOrDefault();
var bar = foo.Bars.First();
foo.Bars.Remove(bar);
ctx.SaveChanges();

从EF加载条,然后将其从集合中删除.

Load bars from EF and just remove them from the collection.

删除(已删除)

var bar = new Bar
{
    BarId = 1
};

ctx.Entry(bar).State = EntityState.Deleted;
ctx.SaveChanges();

在这里,没有从上下文中加载Bar.因此,我们必须告诉EF它已被删除.

Here, Bar was not loaded from the context. So, we have to tell EF that it is deleted.

在您的情况下,您要将更新的对象发送到MVC控制器;因此,您必须告诉EF StoredProcedureReportStoredProcedureParameters已被修改.

In your case, you are sending the updated object to an MVC Controller; so, you have to tell EF that StoredProcedureReport and StoredProcedureParameters are modified.

如果所有属性都被修改,则可以使用:

If all the properties are being modified you can use:

ctx.Entry(foo).State = EntityState.Modified;
//remember to do the same in all children objects

它将所有属性标记为已修改.请注意,如果未在视图上设置某些属性,则会将其更新为空值.

It will mark all properties as modified. Be aware that if some property was not set on view, it will be updated as an empty value.

如果不是所有的属性都被修改,则必须指定要修改的属性.像这样:

If not all the properties are being modified, you have to specify which properties are. Like this:

context.Entry(foo).Property("Description").IsModified = true; 
context.Entry(foo).Property("AnotherProperty").IsModified = true; 

希望有帮助!

这篇关于在实体框架中干净地更新层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆