I have these two tables:
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
))
And These two classes for the tables:
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; }
}
My problem is defining the relationship using the fluent API, as you can see there is a foreign key from Logging to LoggingLevel, but I don’t want the corresponding collection of logs on the LoggingLevel class. I’ve tried a number of combinations of the following, including .WithRequiredDependant and .WithRequiredPrincipal:
modelBuilder.Entity<Logging>()
.HasRequired(l => l.Level)
.WithOptional()
.Map(l => l.MapKey("LoggingLevelName"));
This never ends up getting the join correct, here is data from the LoggingLevel table, and some sample rows from the logging table.
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
Here is sample linq query I’m trying to run:
var results = (from log in db.Loggings
where log.Level.LoggingLevelValue >= 60000
&& log.LogTime >= filterDate
orderby log.LogTime descending
select log);
return results.ToList();
Update results from using :
modelBuilder.Entity<Logging>()
.HasRequired(l => l.Level).WithMany();
Here is the SQL this generates when running my query:
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'
I put ** around the fields in error in the query, bold doesn’t work in code sections though.
Here is my full fluent API configuration:
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();
Well, you want to create a one-to-many relationship, right?
One
LoggingLevelcan have manyLoggingand oneLoggingis required to have oneLoggingLevel.The way you are configuring the relationship, will make EF create it as a one-to-one.
To make it correctly become one-to-many, you have to call
WithManyinstead ofWithOptional:Since the column used as the foreign key is called LogLevel in the database, you have to tell EF by using the
Mapmethod, and call theMapKeymethod with the correct column name.Otherwise it generates the column name by convention. It uses the navigation property name and the name of the key property of the target type, and appends the values.
In your case this results in
Level_LoggingLevelName, which is not right. So you have to map the column name manually.