Сравнение массивов байтов с NHibernate - PullRequest
3 голосов
/ 14 июня 2011

Следующий запрос 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<File>()?

Ответы [ 3 ]

1 голос
/ 22 июня 2011

Из-за того, что ошибка уже указывает на то, что 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>

Toнастроить это я использовал 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();

Удачи!

0 голосов
/ 04 марта 2015

Старый Q, но все еще проблемы с Linq. Таким образом, используя NHibernate и SQLite, при сравнении со значением байтового массива вы можете использовать запрос поверх ограничений или критериев.

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

или

session.CreateCriteria<TestItem>().Add(Restrictions.Eq("Foo", aaa))
0 голосов
/ 24 июня 2011

Я решил проблему, сохранив 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;
    }
}
...