gpt4 book ai didi

entity-framework-4.1 - EF 4.1代码优先:为什么EF不设置此导航属性?

转载 作者:行者123 更新时间:2023-12-04 08:23:39 24 4
gpt4 key购买 nike

这是一个示例场景,说明了我遇到的问题。

这是在SQL 2008中生成数据库的DB脚本:

USE [master]
GO

/****** Object: Database [EFTesting] Script Date: 08/15/2011 09:56:33 ******/
CREATE DATABASE [EFTesting] ON PRIMARY
( NAME = N'EFTesting', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL\DATA\EFTesting.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N'EFTesting_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL\DATA\EFTesting_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO

ALTER DATABASE [EFTesting] SET COMPATIBILITY_LEVEL = 100
GO

USE [EFTesting]
GO

/****** Object: Table [dbo].[Schedule] Script Date: 08/15/2011 09:45:53 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Schedule](
[ScheduleID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Version] [timestamp] NOT NULL,
CONSTRAINT [PK_Schedule] PRIMARY KEY CLUSTERED
(
[ScheduleID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

/****** Object: Table [dbo].[Customer] Script Date: 08/15/2011 09:45:53 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[ScheduleID] [int] NOT NULL,
[Version] [timestamp] NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
[CustomerID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

/****** Object: ForeignKey [FK_Customer_Schedule] Script Date: 08/15/2011 09:45:53 ******/
ALTER TABLE [dbo].[Customer] WITH CHECK ADD CONSTRAINT [FK_Customer_Schedule] FOREIGN KEY([ScheduleID])
REFERENCES [dbo].[Schedule] ([ScheduleID])
GO
ALTER TABLE [dbo].[Customer] CHECK CONSTRAINT [FK_Customer_Schedule]
GO


这是模型,上下文和测试工具的C#代码:

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

namespace Tester
{
public class Context : DbContext
{
public Context(string connectionString) : base(connectionString)
{
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Customer
modelBuilder.Entity<Customer>()
.HasKey(c => c.ID)
.Property(c => c.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("CustomerID");

modelBuilder.Entity<Customer>()
.Property(c => c.Version).IsConcurrencyToken();

modelBuilder.Entity<Customer>()
.HasRequired(c => c.Schedule);

modelBuilder.Entity<Customer>()
.ToTable("Customer");

// Schedule
modelBuilder.Entity<Schedule>()
.HasKey(s => s.ID)
.Property(s => s.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("ScheduleID");

modelBuilder.Entity<Schedule>()
.Property(s => s.Version).IsConcurrencyToken();

modelBuilder.Entity<Schedule>()
.ToTable("Schedule");
}
}

public class Customer
{
public Customer()
{
Schedule = new Schedule();
}

public int ID { get; set; }

public string Name { get; set; }

public int ScheduleID { get; set; }

public Schedule Schedule { get; set; }

public byte[] Version { get; set; }
}

public class Schedule
{
public int ID { get; set; }

public string Name { get; set; }

public byte[] Version { get; set; }
}

public class Program
{
public static void Main(string[] args)
{
// create new customer / schedule
var context = new Context(@"Data Source=.\SQLEXPRESS;Initial Catalog=EFTesting;Integrated Security=True;MultipleActiveResultSets=True");
var customer = new Customer
{
Name = "CUSTOMER",
Schedule = new Schedule
{
Name = "SCHEDULE"
}
};

context.Set<Customer>().Add(customer);
context.SaveChanges();

// pull new customer
context = new Context(@"Data Source=.\SQLEXPRESS;Initial Catalog=EFTesting;Integrated Security=True;MultipleActiveResultSets=True");
var result = context.Set<Customer>().Include(c => c.Schedule).Single(c => c.ID == customer.ID);

// this succeeds
Debug.Assert(result.ScheduleID == customer.Schedule.ID);

// this fails - Schedule is not set to database version, is left as new version from constructor
Debug.Assert(result.Schedule.ID == customer.Schedule.ID);
}
}
}


您可以看到默认的Schedule实例是在Customer构造函数内部创建的,因此它绝不是空引用。但是,问题在于,当EF从数据库加载客户时,如果它不为null,则根本不会设置Schedule引用。

这将导致外键属性ScheduleID与导航属性不同步,并且稍后将导致异常。

谁能解释EF为什么这么做,以及是否有一种方法可以解决它而不改变模型设计?对我来说,即使这是设计使然,但由于框架没有使模型保持同步,这对我来说还是一个错误。

最佳答案

对于您的问题,我没有很好的答案,但是我还是会给您一个机会。

基本上,您不能在构造函数中初始化Schedule属性。通过这样做,EF认为该属性已被修改(设置为新值),因此不会尝试覆盖它。实际上,如果在代码中的断言之前添加另一个context.SaveChanges(),则会看到EF尝试插入在构造函数中创建的新Schedule实体。

我可以建议的唯一解决方法是在类外手动初始化属性,或者更好的方法是创建替代的Customer构造函数,并将默认值构造为protected或private:

public class Customer
{
public Customer(string name)
{
Name = name;
Schedule = new Schedule();
}

protected Customer() { }

public int ID { get; set; }
public string Name { get; set; }
public int ScheduleID { get; set; }
public Schedule Schedule { get; set; }
public byte[] Version { get; set; }
}


EF将使用默认的构造函数,但是您可以在代码中使用其他构造函数。

我明白了您对这似乎是个错误的看法,但我也理解为什么EF会这样做……我想我对此持保留态度。

无论如何,祝你好运!

关于entity-framework-4.1 - EF 4.1代码优先:为什么EF不设置此导航属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7060602/

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