Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有EF 4.1导航属性的ASP.NET MVC_C#_Asp.net Mvc 3_Entity Framework 4.1 - Fatal编程技术网

C# 具有EF 4.1导航属性的ASP.NET MVC

C# 具有EF 4.1导航属性的ASP.NET MVC,c#,asp.net-mvc-3,entity-framework-4.1,C#,Asp.net Mvc 3,Entity Framework 4.1,经过几天的学习,我终于意识到我可能有一个大问题 假设我有两个实体:Pais和UF。它们之间的关系是Pais(0..1)。。。(*)UF。截图: 表示,考虑到我有一个控制器名为 UFController ,它对编辑< 和创建< /代码>有动作,这很好。我的视图使用EditorForhelper(或类似的工具)进行输入,因此当我提交表单时,控制器将收到一个UF对象,其中填充了所有数据(自动),并引用了几乎为空的Pais。我的视图代码(部分): 控制器编辑操作代码: [HttpPost] public

经过几天的学习,我终于意识到我可能有一个大问题

假设我有两个实体:
Pais
UF
。它们之间的关系是
Pais(0..1)。。。(*)UF
。截图:

表示,考虑到我有一个控制器名为<代码> UFController <代码>,它对<代码>编辑< <代码>和<代码>创建< /代码>有动作,这很好。我的视图使用

EditorFor
helper(或类似的工具)进行输入,因此当我提交表单时,控制器将收到一个
UF
对象,其中填充了所有数据(自动),并引用了几乎为空的
Pais
。我的视图代码(部分):

控制器
编辑
操作代码:

[HttpPost]
public ActionResult Edit(UF uf)
{
    try
    {
        if (ModelState.IsValid)
        {
            db.UFs.Attach(uf);
            db.ObjectStateManager.ChangeObjectState(uf, EntityState.Modified);
            db.SaveChanges();

            return this.ClosePage(); // An extension. Just ignore it.
        }
    }
    catch (Exception e)
    {
        this.ModelState.AddModelError("Model", e.Message.ToString());
    }

    return View(uf);
}
当我提交表单时,这就是操作作为
uf
接收的内容:

{TOTALWeb.UF}
    base {System.Data.Objects.DataClasses.EntityObject}: {TOTALWeb.UF}
    (...)
    CodigoGIA: 0
    CodigoIBGE: 0
    Descricao: "Foobar 2001"
    ID: 936
    Pais: {TOTALWeb.Pais}
    PaisReference: {System.Data.Objects.DataClasses.EntityReference<TOTALWeb.Pais>}
原始信息(数据库上的信息)是
uf.Pais.Codigo==716
。所以,现在我收到了最新的信息。控制器未在数据库中升级FK的问题

我不想将EntityState从
uf.Pais
设置为
Modified
,因为实体本身没有更改(我没有更改该条目中的信息),但关系是正确的

换句话说,我要做的是更改FK的值,将
uf.Pais
指向
Pais
的另一个实例。抱歉,不可能将关系状态更改为
Modified
(抛出异常),因此我正在寻找替代解决方案

我在谷歌上看到了很多关于这类问题的话题,但我仍然没有找到一个简单而优雅的解决方案。我在stackoverflow上读到的最后一篇文章:

几天前我问了一个关于类似问题的问题()。当时我不明白EF是如何工作的,所以现在我对很多事情都很清楚(这就是为什么我要提出一个新问题)

对于
Create
操作,我一直在测试此解决方案(由Ladislav在我的另一个问题上提出),但它会生成一个额外的select(这对我们来说可能会很慢):

当我尝试将editedUF附加到当前上下文时抛出异常。我现在正在研究这个想法,试图找到其他解决方案。此外,您说得对,BennyM,将PAI附加到上下文并不会生成额外的SELECT。我不知道当时发生了什么,它真的与数据库没有任何关系


不过,这是一个手动解决方案:我必须为每个FK执行此操作。这就是我想要避免的。你看,有些程序员,即使你解释了100遍,也不会记得对每个FK都这样做。最终我会想到这一点,所以我尽量避免任何可能导致错误的事情(数据库或代码错误),以确保每个人都能在没有任何压力的情况下工作

如果在模型中包含外键。因此,将
PaisId
属性添加到UF实体,您可以直接设置它,它将更新关联

using (var db = new Context())
{
   db.UFs.Attach(editedUF);
   editedUF.PaisId = theForeignKey;
   db.Entry(editedUF).State = EntityState.Modified;
   db.SaveChanges();
}
另外,我已经测试了您在问题中提到的方法,在附加实体时,我没有得到额外的选择。因此,这也是可行的:

using (var db = new Context())
{
   ExistingPais pais = new Pais{Id =theId};
   db.Pais.Attach(pais);
   db.UF.Attach(editedUF);
   editedUF.Pais = pais;
   db.Entry(editedUF).State = EntityState.Modified;
   db.SaveChanges();
}
假设您的代码如下所示:

public class  Pais
{
    public int Id { get; set; }
    public virtual ICollection<UF> UFs { get; set; }
} 

public class UF
{
  public int Id { get; set; }
  public virtual Pais Pais { get; set; }
  public int PaisId { get; set; }
}  
公共类PAI
{
公共int Id{get;set;}
公共虚拟ICollection UFs{get;set;}
} 
公共类用友
{
公共int Id{get;set;}
公共虚拟Pais Pais{get;set;}
公共int PaisId{get;set;}
}  

我在回答我自己的问题,因为我找到了一个简单的解决方案(至少在我的情况下)。我的场景使用很多视图进行数据输入(这意味着我有很多实体)。我需要一个简单易用的解决方案,所以我删除了整个Entities EDMX文件(Ctrl+a,Delete!)

然后,我决定再次添加
pai
UF
实体,但选中用于公开FK属性的复选框。首先,我认为它们不能一起工作,但它们可以,但你需要在如何使用它上小心一点。它们现在与导航属性和公开的FK链接

我无法添加FK属性的原因是因为我是手动添加的。使用“从数据库更新模型”再次检查正确的选项,它工作得完美无缺

在我的编辑视图中,我正在将
Pais
的ID设置为FK属性,而不是
Pais.Codigo
。之所以这样做,是因为FK属性是标量属性,然后我可以检测更改

这是
Pais
输入的当前视图代码(不完全是它,但与此类似):

顺便说一句,
PaisCodigo
是FK。是的,它可能会与
Pais.Codigo
有点混淆,但我们还没有决定任何命名规则。如果您对这个想法有任何建议,我们将不胜感激

最后的
Edit
操作代码如下所示(我删除了错误处理以使其看起来简单!)

这是我提交
editedUF
表格时收到的信息:

{TOTALWeb.UF}
base {System.Data.Objects.DataClasses.EntityObject}: {TOTALWeb.UF}
(...)
CodigoGIA: 0
CodigoIBGE: 0
CodigoPais: 0 <-- new Pais ID!
Descricao: "Foobar 2000"
ID: 902
Pais: {TOTALWeb.Pais}
PaisReference: {System.Data.Objects.DataClasses.EntityReference<TOTALWeb.Pais>}
Sigla: "RI"
Usuarios: {System.Data.Objects.DataClasses.EntityCollection<TOTALWeb.Usuario>}
所以,它已经被填满了。这样做的代价应该是一个查询,但我无法在监视器上捕获它

换句话说,只需公开FK,使用视图对其进行更改,并使用导航属性使代码更加清晰。就这样!:)

谢谢大家,

里卡多


附言:我正在使用EF4.1作为基础。我们不使用SQL Server(至少目前是这样)。我之前说的“监视器”是devArt的dbMonitor,因此我可以看到发送到Oracle数据库的所有查询。再说一次,对于任何英语错误,我深表歉意

我不确定您的
上下文
类的准确程度。My
db
是EF创建的
实体类。另外,
pai
UF
都是根据我的数据库代码生成的。我编辑了我的问题以显示我的尝试。顺便说一句,我没有
条目
using (var db = new Context())
{
   db.UFs.Attach(editedUF);
   editedUF.PaisId = theForeignKey;
   db.Entry(editedUF).State = EntityState.Modified;
   db.SaveChanges();
}
using (var db = new Context())
{
   ExistingPais pais = new Pais{Id =theId};
   db.Pais.Attach(pais);
   db.UF.Attach(editedUF);
   editedUF.Pais = pais;
   db.Entry(editedUF).State = EntityState.Modified;
   db.SaveChanges();
}
public class  Pais
{
    public int Id { get; set; }
    public virtual ICollection<UF> UFs { get; set; }
} 

public class UF
{
  public int Id { get; set; }
  public virtual Pais Pais { get; set; }
  public int PaisId { get; set; }
}  
@Html.EditorFor(m => m.PaisCodigo)
[HttpPost]
public ActionResult Edit(UF editedUF)
{
    if (ModelState.IsValid)
    {
        // Attach the edited UF into the context and change the state to Modified.
        db.UFs.Attach(editedUF);
        db.ObjectStateManager.ChangeObjectState(editedUF, EntityState.Modified);

        // Save changes.
        db.SaveChanges();

        // Call an extension (it's a redirect action to another page, just ignore it).
        return this.ClosePage();
    }
}
{TOTALWeb.UF}
base {System.Data.Objects.DataClasses.EntityObject}: {TOTALWeb.UF}
(...)
CodigoGIA: 0
CodigoIBGE: 0
CodigoPais: 0 <-- new Pais ID!
Descricao: "Foobar 2000"
ID: 902
Pais: {TOTALWeb.Pais}
PaisReference: {System.Data.Objects.DataClasses.EntityReference<TOTALWeb.Pais>}
Sigla: "RI"
Usuarios: {System.Data.Objects.DataClasses.EntityCollection<TOTALWeb.Usuario>}
{TOTALWeb.Pais}
base {System.Data.Objects.DataClasses.EntityObject}: {TOTALWeb.Pais}
(...)
Codigo: 0
CodigoBACEN: 1058
CodigoGIA: 0
CodigoIBGE: null
Descricao: "Brasil"
UFs: {System.Data.Objects.DataClasses.EntityCollection<TOTALWeb.UF>}