gpt4 book ai didi

c# - 为什么日期时间会阻止加载导航属性?

转载 作者:太空狗 更新时间:2023-10-29 20:37:12 25 4
gpt4 key购买 nike

我正在使用针对 SQL Server 2012 数据库的 DbContext POCO 方法使用 Entity Framework 4.3.1。

我在数据库中只有两个表,它们看起来像这样:

tables

注意:数据库中根本没有指定外键 - 我只是在模型中强制执行关系(我无法更改数据库)。

他们每个人都有一行数据,如下所示:

data

我执行了以下查询以确保连接有效:

validation

现在,我有以下实体:

public class Two
{
public long TwoId { get; set; }
public string OneId { get; set; }
public virtual One One { get; set; }
}

public class One
{
public string OneId { get; set; }
public DateTime DeliveryDate { get; set; }
public virtual ICollection<Two> Twos { get; private set; }

public void AddTwo(Two two)
{
if (two == null)
throw new ArgumentNullException("two");

if (Twos == null)
Twos = new List<Two>();

if (!Twos.Contains(two))
Twos.Add(two);

two.One = this;
}
}

这是上下文:

public class TestContext : DbContext
{
public TestContext(string conectionString)
: base(conectionString)
{
Configuration.LazyLoadingEnabled = true;
Ones = Set<One>();
Twos = Set<Two>();
}
public DbSet<One> Ones { get; private set; }
public DbSet<Two> Twos { get; private set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var one = modelBuilder.Entity<One>();
one.ToTable("One");
one.HasKey(d => d.OneId);

var two = modelBuilder.Entity<Two>();
two.ToTable("Two");
two.HasKey(d => new
{
d.OneId,
d.TwoId
});
two.Property(p => p.TwoId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
two.HasRequired(t => t.One)
.WithMany(o => o.Twos)
.HasForeignKey(o => o.OneId);
base.OnModelCreating(modelBuilder);
}
}

当我运行这段代码时,我得到 Why is this printed? 打印到我的控制台 - 我不希望看到导航属性应该被填充(我什至明确地包括它):

using (var ctx = new TestContext(@"......"))
{
const string oneId = "111348718";
var one = ctx.Ones.Single(o => o.OneId.Equals(oneId));

if (one != null)
{
var sdi = ctx
.Twos
.Include(s => s.One)
.Single(s => s.OneId.Equals(oneId));

if (sdi.One == null)
{
Console.WriteLine("Why is this printed?");
}
else
{
Console.WriteLine("This is what I expect");
}
}
}

现在,这真的很奇怪:如果我简单地从 One 类中注释掉 DeliveryDate 属性,它就可以正常工作(我将 This is what I expect 打印到控制台)。

这里有什么问题,我该如何解决?

注意:如果我查看 one 变量的 DeliveryDate 属性,它已正确设置为预期值,因此日期在数据库和 Entity Framework 完全能够实现它。

更多信息:它是一个日期这一事实并不重要 - 如果是,说一个 nvarchar 它仍然失败 - 似乎任何简单的属性都会导致整个事情失败 - 这感觉就像对我来说是个错误...

最佳答案

好的,所以我已经弄清楚了,我认为这是 Entity Framework 中的一个错误,但我可以解决它。这就是它...

Two 表中的 OneId 列末尾有一个空格。

是的 - 想想看 - 这有多糟糕!?

所以我编写了一个 sql 脚本,该脚本在数据库中的每个 nvarchar 列上执行了 LTRIM(RTRIM( 并且一切正常。

现在,鉴于 SQL 服务器不关心空格(正如问题中带有连接的查询所证明的那样),我真的不喜欢 Entity Framework 关心,尤其是因为它在这里完全奇怪且不一致。当然,我调用 Single 获取 sdi 变量填充的那一点应该已经抛出,或者导航属性应该已经填充 - 一个或另一个,但这种行为确实令人困惑(在我看来)- 某些任意属性与鱼的价格有什么关系??

为了完整起见,这里简单地重现了这一点。创建一个新数据库,然后在其上运行此 SQL 脚本:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[One](
[OneId] [nvarchar](10) NOT NULL,
[SomeInt] [int] NOT NULL,
CONSTRAINT [PK_Delivery] PRIMARY KEY CLUSTERED
(
[OneId] 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

CREATE TABLE [dbo].[Two](
[TwoId] [int] NOT NULL,
[OneId] [nvarchar](10) NOT NULL,
CONSTRAINT [PK_DeliveryItem] PRIMARY KEY CLUSTERED
(
[TwoId] ASC,
[OneId] 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

INSERT INTO Two(TwoId, OneId) VALUES (1, '1 ')
INSERT INTO One(OneId, SomeInt) VALUES ('1', 1.0)

现在创建一个 C# 控制台应用程序,添加对 EntityFramework(版本 4.3.1)和 System.Data.Entity 程序集的引用,将此代码放入并运行它 - 它将打印 SHOULD NOT BE PRINTED!!!

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;

namespace EFTest
{
public class Two
{
public int TwoId { get; set; }
public string OneId { get; set; }
public virtual One One { get; set; }
}

public class One
{
public string OneId { get; set; }
public virtual ICollection<Two> Twos { get; private set; }

// Comment out this property and it will work
public int SomeInt { get; set; }

public void AddTwo(Two two)
{
if (two == null)
throw new ArgumentNullException("two");

if (Twos == null)
Twos = new List<Two>();

if (!Twos.Contains(two))
Twos.Add(two);

two.One = this;
}
}

public class Context : DbContext
{
public Context(string connectionString)
: base(connectionString)
{
Configuration.LazyLoadingEnabled = true;
Ones = Set<One>();
Twos = Set<Two>();
}

public DbSet<One> Ones { get; private set; }
public DbSet<Two> Twos { get; private set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<One>()
.HasKey(d => d.OneId)
.ToTable("One");

var two = modelBuilder.Entity<Two>();
two.ToTable("Two");
two.HasKey(d => new
{
d.OneId,
d.TwoId
});

two.Property(d => d.TwoId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

two.HasRequired(m => m.One)
.WithMany(t => t.Twos)
.HasForeignKey(d => d.OneId);

base.OnModelCreating(modelBuilder);
}
}

internal class Program
{
private static void Main()
{
using (var ctx = new Context(@"your connection string"))
{
const string oneId = "1";
var one = ctx.Ones.Single(o => o.OneId.Equals(oneId));

if (one == null)
{
Console.WriteLine("No row with one ID in the database");
return;
}

var two = ctx
.Twos
.Include(s => s.One)
.Single(s => s.OneId.Equals(oneId));

Console.WriteLine(two.One == null
? "SHOULD NOT BE PRINTED!!!"
: "SHOULD BE PRINTED");
}
}
}
}

然后执行以下操作之一:

  • 注释掉 One 类的 SomeInt 属性
  • 删除数据库中的空间(UPDATE Two SET OneId = RTRIM(OneId))。

两者都可以(显然,修剪是现实生活中唯一合理的解决方法)。

关于c# - 为什么日期时间会阻止加载导航属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11776666/

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