实体框架EdmFunction导入无法识别

时间:2011-08-20 01:10:44

标签: c# sql-server entity-framework

首先,我之前有一个问题,虽然看起来非常相似,但问题不一样,请看一下:Function import from SQL Server to Entity Framework runtime exception

此函数HammingDistance,用于在SQL Server中创建标量函数后运行良好,然后使用EDM函数映射导入实体框架。我一直在建立我的网站,在网站和EDMX周围做了一些分歧,但没有碰到这个功能并保证它的安全。这是SQL Server上的SQL函数:

ALTER function [dbo].[HammingDistance]
(@first bigint, @second bigint) returns int
as
begin
    declare @xor bigint = @first ^ @second;
    declare @one bigint = 1;
    declare @diff int = 0;
    declare @and bigint;
    while (@xor != 0)
        begin
        set @and = @xor & @one;
        if(@and = @one)
            begin
            set @diff = @diff + 1;
            end
        set @xor = @xor / 2;
        end
    return @diff;
end

这是我的C#代码:

声明:

public static class EdmFunctionMapping
{

    [EdmFunction("MainDB.Store", "HammingDistance")]
    public static int GetHammingDistance(long hash1, long hash2)
    {
        throw new NotSupportedException("This method can only be used in a LINQ-to-Entities query");
    }
}

用法:

var query = (from p in VisibleObjects.OfType<Photo>()
                     let hd = EdmFunctionMapping.GetHammingDistance(targetPhoto.Analysis.Hash, p.Analysis.Hash)
                     let cd = Math.Abs(targetPhoto.Analysis.High.Red - p.Analysis.High.Red)+
                     Math.Abs(targetPhoto.Analysis.High.Green - p.Analysis.High.Green)+
                     Math.Abs(targetPhoto.Analysis.High.Blue - p.Analysis.High.Blue) +
                     Math.Abs(targetPhoto.Analysis.Low.Red - p.Analysis.Low.Red) +
                     Math.Abs(targetPhoto.Analysis.Low.Green - p.Analysis.Low.Green) +
                     Math.Abs(targetPhoto.Analysis.Low.Blue - p.Analysis.Low.Blue)
                     where
                     hd < 5 ||
                     (hd < 15 || cd < 100)
                     orderby hd ascending
                     select p).Take(50);
        return query.ToList();

其中VisibleObjects不评估Enumerable。无论如何它在这里:

static IEnumerable<GlobalObject> VisibleObjects
    {
        get
        {
            return from obj in db.GlobalObjectSet where obj.IsVisible && !obj.SiteUser.IsDeactivated orderby obj.ID descending select obj;
        }
    }

大概两三个星期以前的一切都工作了,在那个时间间隔内我添加/删除了很多东西,并没有检查汉明距离是否有效,所以我不知道它什么时候破坏了。它不再起作用,就像EdmFunction属性不存在一样,试图在我的应用程序中进行评估并抛出我写的异常,说它只能用于L2E查询。我已经对所有内容进行了双重检查,甚至完全重新创建了数据库并从EDMX生成,并使用数据库中的更新模型创建并导入了该函数,并且它在EDMX中看到了该函数,并且它(显然)在EDMX文件中可用SSDL部分如:

    <Function Name="HammingDistance" ReturnType="int" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
      <Parameter Name="first" Type="bigint" Mode="In" />
      <Parameter Name="second" Type="bigint" Mode="In" />
    </Function>

但是当涉及到应用程序时,它就不会映射到EDM!多次尝试,从头开始创建所有数据库,没有任何变化,它会在query.ToList()中抛出异常,并且没有内部异常(它有意义,因为它抛出我自己的异常,不应该由应用程序执行)。我不知道问题的根源,我错过了一些明显的东西吗?

1 个答案:

答案 0 :(得分:3)

如果它无法识别您的Edm映射函数,请确保您不会在某处意外将查询更改为linq-to-objects,因为这正是您可以看到该错误的原因。要验证这一点,只需尝试创建另一个测试查询,它将直接实体访问并调用您的函数。类似的东西:

long hash = targetPhoto.Analysis.Hash;
var query = from p in db.GlobalObjectSet.OfType<Photo>()
            select new { EdmFunctionMapping.GetHammingDistance(hash, p.Analysis.Hash) }; 

如果这样的查询通过,你肯定有我提到的问题。

修改

我想我现在看到了问题。您的VisibleObjects返回IEnumerable =&gt; LINQ到对象。试试这个:

public static IQueryable<GlobalObject> GetVisibleObjects(this IQueryable<GlobalObject> query) 
{
    return from obj in query 
           where obj.IsVisible && 
                 !obj.SiteUser.IsDeactivated 
           orderby obj.ID descending 
           select obj;
}

并调用您的方法:

from p in db.GlobalObjectSet.GetVisibleObjects().OfType<Photo>() ...