Mat*_*sca 16 .net c# sql-server orm entity-framework
我们在业务解决方案中使用EF 5.0作为我们的首选ORM,以n层方式构建,所有内容都解耦,并且使用ninject构建了一个很好的组合根.
最近,我们一直在构建一个使用下面分区的数据库,我们在DATE列上有一些重要的索引.
这些列在Sql Server 2008上正确声明.我们还在EF映射中添加了正确的数据类型和HasColumnType("Date")指令.
仍然,当通过Linq to Entities查询表时,我们过滤日期的参数是由类型创建的DateTime2,甚至列也会DateTime2在查询中强制转换,因此类型与参数匹配.
这种行为有几个问题.首先,如果我告诉EF引擎数据库中的列是DATE为什么要将其转换为DateTime2?
其次,此强制转换使数据库忽略索引,因此不使用分区.我们每个物理分区有一年,如果我问一个日期范围,比方说,2013年2月到2013年3月,扫描应该仅在一个物理分区上进行.如果手动使用正确的数据类型DATE但是对DateTime2所有分区进行扫描,则它可以正常工作,从而大大降低了性能.
现在,我确定我错过了一些东西,因为微软ORM在Microsoft Sql Server上不能正常工作会相当愚蠢.
我一直无法找到有关EF如何在查询中使用正确数据类型的任何文档,所以我在这里问.任何帮助将不胜感激.
谢谢.
我不相信这在实体框架中是可能的。 这个请求的增强功能可能会满足您的需要。 此 MSDN 页面显示了 SQL Server 类型和 CLR 类型之间的映射。请注意,date受支持并映射到DateTime,但由于多种 SQL 类型映射到同一 CLR 类型,因此 EF 显然会选择一种 SQL 类型作为CLR 类型的首选等效类型。
您可以将选择代码包装在存储过程中吗?如果是这样,这似乎是一个合理的解决方案。您可以使用DbSet{T}.SqlQuery通过执行 sp 来具体化对象。
以下简短的控制台应用程序演示了这个概念。请注意相关实体如何成功延迟加载。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
namespace ConsoleApplication1
{
[Table("MyEntity")]
public class MyEntity
{
private Collection<MyRelatedEntity> relatedEntities;
[Key]
public virtual int MyEntityId { get; set; }
[DataType(DataType.Date)]
public virtual DateTime MyDate { get; set; }
[InverseProperty("MyEntity")]
public virtual ICollection<MyRelatedEntity> RelatedEntities
{
get
{
if (this.relatedEntities == null)
{
this.relatedEntities = new Collection<MyRelatedEntity>();
}
return this.relatedEntities;
}
}
public override string ToString()
{
return string.Format("Date: {0}; Related: {1}", this.MyDate, string.Join(", ", this.RelatedEntities.Select(q => q.SomeString).ToArray()));
}
}
public class MyRelatedEntity
{
[Key]
public virtual int MyRelatedEntityId { get; set; }
public virtual int MyEntityId { get; set; }
[ForeignKey("MyEntityId")]
public virtual MyEntity MyEntity { get; set; }
public virtual string SomeString { get;set;}
}
public class MyContext : DbContext
{
public DbSet<MyEntity> MyEntities
{
get { return this.Set<MyEntity>(); }
}
}
class Program
{
const string SqlQuery = @"DECLARE @date date; SET @date = @dateIn; SELECT * FROM MyEntity WHERE MyDate > @date";
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
using (MyContext context = new MyContext())
{
context.MyEntities.Add(new MyEntity
{
MyDate = DateTime.Today.AddDays(-2),
RelatedEntities =
{
new MyRelatedEntity { SomeString = "Fish" },
new MyRelatedEntity { SomeString = "Haddock" }
}
});
context.MyEntities.Add(new MyEntity
{
MyDate = DateTime.Today.AddDays(1),
RelatedEntities =
{
new MyRelatedEntity { SomeString = "Sheep" },
new MyRelatedEntity { SomeString = "Cow" }
}
});
context.SaveChanges();
}
using (MyContext context = new MyContext())
{
IEnumerable<MyEntity> matches = context.MyEntities.SqlQuery(
SqlQuery,
new SqlParameter("@dateIn", DateTime.Today)).ToList();
// The implicit ToString method call here invokes lazy-loading of the related entities.
Console.WriteLine("Count: {0}; First: {1}.", matches.Count(), matches.First().ToString());
}
Console.Read();
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3301 次 |
| 最近记录: |