实体框架5查询中的数据类型错误

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如何在查询中使用正确数据类型的任何文档,所以我在这里问.任何帮助将不胜感激.

谢谢.

Oll*_*lly 4

我不相信这在实体框架中是可能的。 这个请求的增强功能可能会满足您的需要。 此 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)