gpt4 book ai didi

c# - Entity Framework 4.1 代码优先和自动映射器问题

转载 作者:行者123 更新时间:2023-11-30 15:06:28 25 4
gpt4 key购买 nike

考虑这个简单的模型和 View 模型场景:

public class SomeModel
{
public virtual Company company {get; set;}
public string name {get; set;}
public string address {get; set;}

//some other few tens of properties
}

public class SomeViewModel
{
public Company company {get; set;}
public string name {get; set;}
public string address {get; set;}
//some other few tens of properties
}

出现的问题是:

我有一个不需要公司的编辑页面,所以我不从数据库中获取它。现在,当提交表单时,我会:

SomeModel destinationModel = someContext.SomeModel.Include("Company").Where( i => i.Id == id) // assume id is available from somewhere.

然后我做一个

Company oldCompany = destinationModel.company; // save it before mapper assigns it null

Mapper.Map(sourceViewModel,destinationModel);

//After this piece of line my company in destinationModel will be null because sourceViewModel's company is null. Great!!
//so I assign old company to it

destinationModel.company = oldCompany;

context.Entry(destinationModel).State = EntityState.Modified;

context.SaveChanges();

问题是,即使我将 oldCompany 分配给我的公司,它在保存更改后在数据库中仍然为空。

注意:

如果我改变这些行:

destinationModel.company = oldCompany;

context.Entry(destinationModel).State = EntityState.Modified;

context.SaveChanges();

对这些:

context.Entry(destinationModel).State = EntityState.Modified;

destinationModel.company = oldCompany;

context.Entry(destinationModel).State = EntityState.Modified;

context.SaveChanges();

请注意,我更改了 2 次状态,效果很好。可能是什么问题?这是 ef 4.1 错误吗?

这是解决该问题的示例控制台应用程序:

using System;
using System.Linq;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using AutoMapper;

namespace Slauma
{
public class SlaumaContext : DbContext
{
public DbSet<Company> Companies { get; set; }
public DbSet<MyModel> MyModels { get; set; }

public SlaumaContext()
{
this.Configuration.AutoDetectChangesEnabled = true;
this.Configuration.LazyLoadingEnabled = true;
}
}

public class MyModel
{
public int Id { get; set; }
public string Foo { get; set; }

[ForeignKey("CompanyId")]
public virtual Company Company { get; set; }

public int? CompanyId { get; set; }
}

public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}


public class MyViewModel
{
public string Foo { get; set; }

public Company Company { get; set; }

public int? CompanyId { get; set; }
}

class Program
{
static void Main(string[] args)
{

Database.SetInitializer<SlaumaContext>(new DropCreateDatabaseIfModelChanges<SlaumaContext>());

SlaumaContext slaumaContext = new SlaumaContext();

Company company = new Company { Name = "Microsoft" };
MyModel myModel = new MyModel { Company = company, Foo = "Foo"};

slaumaContext.Companies.Add(company);
slaumaContext.MyModels.Add(myModel);
slaumaContext.SaveChanges();

Mapper.CreateMap<MyModel, MyViewModel>();
Mapper.CreateMap<MyViewModel, MyModel>();


//fetch the company
MyModel dest = slaumaContext.MyModels.Include("Company").Where( c => c.Id == 1).First(); //hardcoded for demo

Company oldCompany = dest.Company;

//creating a viewmodel
MyViewModel source = new MyViewModel();
source.Company = null;
source.CompanyId = null;
source.Foo = "foo hoo";

Mapper.Map(source, dest); // company null in dest


//uncomment this line then only it will work else it won't is this bug?
//slaumaContext.Entry(dest).State = System.Data.EntityState.Modified;

dest.Company = oldCompany;

slaumaContext.Entry(dest).State = System.Data.EntityState.Modified;
slaumaContext.SaveChanges();

Console.ReadKey();

}
}
}

最佳答案

默认情况下,Automapper 总是更新从源实例到目标实例的每个属性。因此,如果您不想覆盖您的 Company 属性,那么您必须为您的映射器显式配置它:

Mapper.CreateMap<MyViewModel, MyModel>().ForMember(m => m.Company, c => c.UseDestinationValue());

到目前为止,与 EF 无关。但是,如果您将其与 EF 一起使用,则必须始终如一地使用导航属性 Company 和 CompanyId:您还需要在映射期间使用 CompanyId 的目标值:

Mapper.CreateMap<MyViewModel, MyModel>().ForMember(m => m.CompanyId, c => c.UseDestinationValue());

编辑:但问题不在于您的公司为空,而是在重置后它在数据库中仍然为空。这是因为如果您拥有像“CompanyId”这样的显式 Id 属性,则必须维护它。所以仅仅调用 destinationModel.company = oldCompany; 是不够的,你还需要调用 destinationModel.companyId = oldCompany.Id;

并且因为您从上下文中检索了目标实体,它已经在为您进行更改跟踪,因此无需设置 EntityState.Modified。

编辑:您修改的样本:

Mapper.CreateMap<MyModel, MyViewModel>();
Mapper.CreateMap<MyViewModel, MyModel>();

//fetch the company
MyModel dest = slaumaContext.MyModels.Include("Company").Where(c => c.Id == 18).First(); //hardcoded for demo

var oldCompany = dest.Company;

//creating a viewmodel
MyViewModel source = new MyViewModel();
source.Company = null;
source.CompanyId = null;
source.Foo = "fdsfdf";

Mapper.Map(source, dest); // company null in dest

dest.Company = oldCompany;
dest.CompanyId = oldCompany.Id;

slaumaContext.SaveChanges();

关于c# - Entity Framework 4.1 代码优先和自动映射器问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7806431/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com