字节数组与 NHibernate 的比较

发布于 2024-11-15 03:59:06 字数 356 浏览 5 评论 0原文

以下 Linq to NHibernate 查询会导致 System.NotSupportedException

IEnumerable<File> FindByMd5(byte[] md5)
{
    return this.Session.Query<File>().Where(f => f.Md5.SequenceEqual(md5)).ToList();
}

我应该如何使用 Linq to NHibernate 或 QueryOver() 来执行此操作?

The following Linq to NHibernate query results in a System.NotSupportedException.

IEnumerable<File> FindByMd5(byte[] md5)
{
    return this.Session.Query<File>().Where(f => f.Md5.SequenceEqual(md5)).ToList();
}

How should I do this using Linq to NHibernate or QueryOver<File>()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一枫情书 2024-11-22 03:59:06

由于该错误已经表明 NHibernate 不支持该功能。我将创建一个命名查询并求解查询中的方程。我已经使用 MySQL 对其进行了测试(使用常见的用户名和密码比较作为示例),并且以下语句返回所需的行(密码是 BINARY(32) 字段):

SELECT * FROM `user` WHERE `password` = MD5('test');

使用 MSSQL 您可以执行以下操作:

SELECT * FROM [user] WHERE [password] = HASHBYTES('MD5', 'test')

因此,将其扩展为命名查询您将创建一个 .hbm.xml 文件,如“User.hbm.xml”,其中包含以下内容:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="My.Model" namespace="My.Model">
  <sql-query name="GetUserByCredentials">
    <return class="My.Model.User, My.Model" />
    <![CDATA[
      SELECT * FROM User WHERE Username = :Username AND Password = MD5(:Password)
    ]]>
  </sql-query>
</hibernate-mapping>

为了配置它,我使用了 Fluent NHibernate,但仅使用普通的 NHibernate 也可以实现类似的操作:

Fluently.Configure()
    .Database(MySqlConfiguration.Standard
        .ConnectionString(x => x.FromConnectionStringWithKey("Test"))
        .AdoNetBatchSize(50))
    .Cache(c => c
        .UseQueryCache()
        .ProviderClass<HashtableCacheProvider>())
    .Mappings(m =>
    {
        m.FluentMappings.AddFromAssemblyOf<IHaveFluentNHibernateMappings>().Conventions.Add(ForeignKey.EndsWith("Id"));
        m.HbmMappings.AddFromAssemblyOf<IHaveFluentNHibernateMappings>();
    })
    .BuildConfiguration();

此语句查找程序集中的“.hbm.xml”文件,其接口名为“IHaveFluentNHibernateMappings”。

有了此文件,您可以在会话级别执行以下操作:

public User GetUserByCredentials(string username, string password)
{
    IQuery query = Session.GetNamedQuery("GetUserByCredentials");
    query.SetParameter("Username", username);
    query.SetParameter("Password", password);

    return query.UniqueResult<User>();
}

通过调用 GetUserByCredentials 方法,将执行自定义查询。

正如您所看到的,密码是一个字符串,因此您需要首先使用以下命令将 MD5 字节数组转换为字符串:

System.Text.StringBuilder s = new System.Text.StringBuilder();
foreach (byte b in md5ByteArray)
{
   s.Append(b.ToString("x2").ToLower());
}
password = s.ToString();

祝您好运!

Due to the fact that the error is already indicating that NHibernate does not support that feature. I would create a named query and solve the equation within a query. I have tested it with MySQL (using a common username and password comparison as example) and the following statement returns the desired row (password is a BINARY(32) field):

SELECT * FROM `user` WHERE `password` = MD5('test');

Using MSSQL you can do:

SELECT * FROM [user] WHERE [password] = HASHBYTES('MD5', 'test')

So to extend this to a named query you would create an .hbm.xml file like 'User.hbm.xml' with the following content:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="My.Model" namespace="My.Model">
  <sql-query name="GetUserByCredentials">
    <return class="My.Model.User, My.Model" />
    <![CDATA[
      SELECT * FROM User WHERE Username = :Username AND Password = MD5(:Password)
    ]]>
  </sql-query>
</hibernate-mapping>

To configure this I used Fluent NHibernate but something similar would be possible with just plain NHibernate:

Fluently.Configure()
    .Database(MySqlConfiguration.Standard
        .ConnectionString(x => x.FromConnectionStringWithKey("Test"))
        .AdoNetBatchSize(50))
    .Cache(c => c
        .UseQueryCache()
        .ProviderClass<HashtableCacheProvider>())
    .Mappings(m =>
    {
        m.FluentMappings.AddFromAssemblyOf<IHaveFluentNHibernateMappings>().Conventions.Add(ForeignKey.EndsWith("Id"));
        m.HbmMappings.AddFromAssemblyOf<IHaveFluentNHibernateMappings>();
    })
    .BuildConfiguration();

This statement looks for the ".hbm.xml" files in the assembly with the interface named "IHaveFluentNHibernateMappings"

With this in place you can do the following at session level:

public User GetUserByCredentials(string username, string password)
{
    IQuery query = Session.GetNamedQuery("GetUserByCredentials");
    query.SetParameter("Username", username);
    query.SetParameter("Password", password);

    return query.UniqueResult<User>();
}

And by calling the the GetUserByCredentials method, the custom query will be executed.

As you can see password is a string, so you need to convert your MD5 byte array to a string first by using:

System.Text.StringBuilder s = new System.Text.StringBuilder();
foreach (byte b in md5ByteArray)
{
   s.Append(b.ToString("x2").ToLower());
}
password = s.ToString();

Good luck!

深海蓝天 2024-11-22 03:59:06

老Q,但是 Linq 仍然有问题。因此,使用 NHibernate 和 SQLite,当与字节数组值进行比较时,您可以使用限制或条件查询。

session.QueryOver<TestItem>().WhereRestrictionOn(i => i.Foo).IsBetween(aaa).And(aaa);

或者

session.CreateCriteria<TestItem>().Add(Restrictions.Eq("Foo", aaa))

Old Q but, still issues with Linq. So, using NHibernate and SQLite, when comparing against a byte array value, you can use query over restrictions or criterias.

session.QueryOver<TestItem>().WhereRestrictionOn(i => i.Foo).IsBetween(aaa).And(aaa);

or

session.CreateCriteria<TestItem>().Add(Restrictions.Eq("Foo", aaa))
挽梦忆笙歌 2024-11-22 03:59:06

我通过将 MD5 存储为字符串解决了这个问题。

public class PersistedFile
{
    public virtual int Id { get; set; }
    public virtual string Path { get; set; }
    public virtual string Md5 { get; set; }
}

使用此方法保存文件:

public PersistedFile Save(string filePath)
{
    using (var fileStream = new FileStream(filePath, FileMode.Open))
    {
        var bytes = MD5.Create().ComputeHash(fileStream);

        using (var transaction = this.Session.BeginTransaction())
        {
            var newFile = new PersistedFile
            {
                Md5 = BitConverter.ToString(bytes),
                Path = filePath,
            };
            this.Session.Save(newFile);
            transaction.Commit();
            return newFile;
        }
    }
}

使用此方法检索文件:

public IEnumerable<PersistedFile> FindByMd5(string md5)
{
    using (var transaction = this.Session.BeginTransaction())
    {
        var files = this.Session.Query<PersistedFile>().Where(f => f.Md5 == md5).ToList();
        transaction.Commit();
        return files;
    }
}

I’ve solved the problem by storing the MD5 as a string.

public class PersistedFile
{
    public virtual int Id { get; set; }
    public virtual string Path { get; set; }
    public virtual string Md5 { get; set; }
}

Files are saved using this method:

public PersistedFile Save(string filePath)
{
    using (var fileStream = new FileStream(filePath, FileMode.Open))
    {
        var bytes = MD5.Create().ComputeHash(fileStream);

        using (var transaction = this.Session.BeginTransaction())
        {
            var newFile = new PersistedFile
            {
                Md5 = BitConverter.ToString(bytes),
                Path = filePath,
            };
            this.Session.Save(newFile);
            transaction.Commit();
            return newFile;
        }
    }
}

Files are retrieved using this one:

public IEnumerable<PersistedFile> FindByMd5(string md5)
{
    using (var transaction = this.Session.BeginTransaction())
    {
        var files = this.Session.Query<PersistedFile>().Where(f => f.Md5 == md5).ToList();
        transaction.Commit();
        return files;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文