【问题标题】:Entity Framework One To Many one sided join实体框架一对多单向连接
【发布时间】:2013-01-20 12:33:09
【问题描述】:

我有这两张表:

CREATE TABLE [MIS].[Logging](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [MachineName] [nvarchar](255) NULL,
    [LogSource] [nvarchar](255) NOT NULL,
    [LogSourceVersion] [nvarchar](255) NULL,
    [LogLevel] [nvarchar](255) NOT NULL,
    [LogMessage] [nvarchar](max) NOT NULL,
    [LogDetailLocation] [nvarchar](255) NULL,
    [LogTime] [datetime] NOT NULL,
 CONSTRAINT [PK_Logging] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
))


CREATE TABLE [MIS].[LoggingLevels](
    [LoggingLevelName] [nvarchar](255) NOT NULL,
    [LoggingLevelValue] [int] NULL,
 CONSTRAINT [PK_LoggingLevels] PRIMARY KEY CLUSTERED 
(
    [LoggingLevelName] ASC
)) 

还有这两个表类:

public class Logging
{
    public int Id { get; set; }
    public string MachineName { get; set; }
    public string LogSource { get; set; }
    public string LogSourceVersion { get; set; }
public string LogDetailLocation { get; set; }
public DateTime LogTime { get; set; }
    public string LogMessage { get; set; }

//public string LogLevel { get; set; }
public LoggingLevel Level { get; set; }
}

public class LoggingLevel
{
    public int LoggingLevelValue { get; set; }
    public string LoggingLevelName { get; set; }
}

我的问题是使用 fluent API 定义关系,您可以看到从 Logging 到 LoggingLevel 的外键,但我不希望 LoggingLevel 类上的相应日志集合。我尝试了以下几种组合,包括.WithRequiredDependant.WithRequiredPrincipal

    modelBuilder.Entity<Logging>()
                .HasRequired(l => l.Level)
                .WithOptional()
                .Map(l => l.MapKey("LoggingLevelName"));

这永远不会使连接正确,这是来自 LoggingLevel 表的数据,以及来自日志记录表的一些示例行。

LoggingLevelName LoggingLevelValue
---------------- -----------------
ALL              -2147483648
DEBUG            30000
INFO             40000
WARN             60000
ERROR            70000
FATAL            110000
OFF              2147483647


id          MachineName LogSource LogSourceVersion LogLevel   LogMessage LogDetailLocation LogTime
----------- ----------- --------- ---------------- ---------- ---------- ----------------- -----------------------
115170694   redacted    redacted  17               INFO       redacted   redacted          2013-01-29 04:00:02.420
115170695   redacted    redacted  (null)           INFO       redacted   redacted          2013-01-29 04:00:03.587
115170696   redacted    redacted  (null)           INFO       redacted   redacted          2013-01-29 04:01:01.357
115170697   redacted    redacted  NULL             INFO       redacted   redacted          2013-01-29 04:01:01.357
115170698   redacted    redacted  10               INFO       redacted   redacted          2013-01-29 04:01:01.933
115170699   redacted    redacted  17               INFO       redacted   redacted          2013-01-29 04:01:33.320
115170700   redacted    redacted  (null)           INFO       redacted   redacted          2013-01-29 04:02:29.990
115170701   redacted    redacted  (null)           INFO       redacted   redacted          2013-01-29 04:02:30.000
115170702   redacted    redacted  (null)           INFO       redacted   redacted          2013-01-29 04:02:30.040
115170703   redacted    redacted  (null)           INFO       redacted   redacted          2013-01-29 04:02:30.243

这是我尝试运行的示例 linq 查询:

    var results = (from log in db.Loggings
                   where log.Level.LoggingLevelValue >= 60000
                         && log.LogTime >= filterDate
                   orderby log.LogTime descending
                   select log);
    return results.ToList();

使用更新结果:

    modelBuilder.Entity<Logging>()
                .HasRequired(l => l.Level).WithMany();

这是运行我的查询时生成的 SQL:

exec sp_executesql N'SELECT 
[Project1].[Id] AS [Id], 
[Project1].[MachineName] AS [MachineName], 
[Project1].[LogSource] AS [LogSource], 
[Project1].[LogSourceVersion] AS [LogSourceVersion], 
[Project1].[LogDetailLocation] AS [LogDetailLocation], 
[Project1].[LogTime] AS [LogTime], 
[Project1].[LogMessage] AS [LogMessage], 
[Project1].**[Level_LoggingLevelName]** AS [Level_LoggingLevelName]
FROM ( SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[MachineName] AS [MachineName], 
    [Extent1].[LogSource] AS [LogSource], 
    [Extent1].[LogSourceVersion] AS [LogSourceVersion], 
    [Extent1].[LogDetailLocation] AS [LogDetailLocation], 
    [Extent1].[LogTime] AS [LogTime], 
    [Extent1].[LogMessage] AS [LogMessage], 
    [Extent1].**[Level_LoggingLevelName]** AS [Level_LoggingLevelName]
    FROM  [MIS].[Logging] AS [Extent1]
    INNER JOIN [MIS].[LoggingLevels] AS [Extent2] ON [Extent1].[Level_LoggingLevelName] = [Extent2].[LoggingLevelName]
    WHERE ([Extent2].[LoggingLevelValue] >= @p__linq__0) AND ( CAST( [Extent1].[LogTime] AS datetime2) >= @p__linq__1)
)  AS [Project1]
ORDER BY [Project1].[LogTime] DESC',N'@p__linq__0 int,@p__linq__1 datetime2(7)',@p__linq__0=60000,@p__linq__1='2013-02-04 00:00:00'

我在查询中错误的字段周围加上了**,但粗体在代码部分中不起作用。

这是我完整的 fluent API 配置:

    modelBuilder.Entity<Logging>().ToTable("Logging", "MIS");
    modelBuilder.Entity<Logging>().HasKey(l => l.Id);

    modelBuilder.Entity<LoggingLevel>().ToTable("LoggingLevels", "MIS");
    modelBuilder.Entity<LoggingLevel>().HasKey(ll => ll.LoggingLevelName);

    modelBuilder.Entity<ProblemResolution>().ToTable("ProblemResolutions", "MIS");
    modelBuilder.Entity<ProblemResolution>().HasKey(r => r.Id);

    modelBuilder.Entity<Logging>()
                .HasRequired(l => l.Level).WithMany();

【问题讨论】:

  • 代码首先应该生成相当于定义的 2 表?
  • 我没有生成表,它是一个现有的数据库,但是不,我不希望代码先生成任何东西。
  • 我知道我可以使用从 LogLevel 到 LoggingLevelName 的连接以不同的方式执行此操作,但我想了解如何使用类上的外键和属性来执行此操作。
  • 对不起,我不明白你到底想做什么
  • 使用我定义的表和它们的类,我试图让底部的 linq 查询在不生成无效 SQL 的情况下运行。

标签: linq-to-entities ef-code-first entity-framework-5 foreign-key-relationship


【解决方案1】:

嗯,你想创建一个一对多的关系,对吧?

一个LoggingLevel 可以有多个Logging,一个Logging 必须有一个LoggingLevel

您配置关系的方式将使 EF 以一对一的方式创建它。

要使其正确地变为一对多,您必须调用WithMany 而不是WithOptional

HasRequired(l => l.Level).WithMany().Map(p => p.MapKey("LogLevel"))

由于用作外键的列在数据库中称为LogLevel,因此必须使用Map方法告诉EF,并以正确的列名调用MapKey方法。

否则它会按照约定生成列名。它使用导航属性名称和目标类型的键属性名称,并附加值。

在您的情况下,这会导致 Level_LoggingLevelName,这是不正确的。所以你必须手动映射列名。

【讨论】:

  • 仍然无法正确生成 SQL,它会尝试查询列 Level_LoggingLevelName,请参阅上面的更新。
  • mapkey 成功了,谢谢。你知道一个很好的文档网站吗,我用谷歌搜索了,但我得到的只是 MSDN 上的基本 FK 关系资料,没有做这种映射。
  • 我有本书Programming Entity Framework: Code First,其中解释了此类内容。我不知道任何网站,对不起..
  • 谢谢彼得,我去看看这本书。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-02
相关资源
最近更新 更多