Я пытаюсь выяснить, почему я получаю недопустимое исключение броска с NHibernate со следующим кодом:NHibernate недействительным залиты на заказ PrimitiveType
AutoMap.Source(new TypeSource(recordDescriptors))
.Conventions.Add(new EncryptedStringConvention());
.
[AttributeUsage(AttributeTargets.Property)]
public class EncryptedDbString : Attribute { }
.
public class EncryptedStringConvention : IPropertyConvention {
public void Apply(IPropertyInstance instance) {
if (!instance.Property.MemberInfo.IsDefined(typeof(EncryptedDbString), false))
return;
var propertyType = instance.Property.PropertyType;
var generic = typeof(EncryptedStringType<>);
var specific = generic.MakeGenericType(propertyType);
instance.CustomType(specific);
}
}
.
[Serializable]
public class EncryptedStringType<T> : PrimitiveType
{
const int MaxStringLen = 1000000000;
public EncryptedStringType() : this(new StringSqlType(MaxStringLen)) { }
public EncryptedStringType(SqlType sqlType) : base(sqlType) { }
public override string Name {
get { return typeof(T).Name; }
}
public override Type ReturnedClass {
get { return typeof(T); }
}
public override Type PrimitiveClass {
get { return typeof(T); }
}
public override object DefaultValue {
get { return default(T); }
}
public override object Get(IDataReader rs, string name) {
return Get(rs, rs.GetOrdinal(name));
}
public override void Set(IDbCommand cmd, object value, int index) {
if (cmd == null) throw new ArgumentNullException("cmd");
if (value == null) {
((IDataParameter)cmd.Parameters[index]).Value = null;
}
else {
((IDataParameter)cmd.Parameters[index]).Value = Encryptor.EncryptString((string)value);
}
}
public override object Get(IDataReader rs, int index) {
if (rs == null) throw new ArgumentNullException("rs");
var encrypted = rs[index] as string;
if (encrypted == null) return null;
return Encryptor.DecryptString(encrypted);
}
public override object FromStringValue(string xml) {
// i don't think this method actually gets called for string (i.e. non-binary) storage
throw new NotImplementedException();
}
public override string ObjectToSQLString(object value, Dialect dialect) {
// i don't think this method actually gets called for string (i.e. non-binary) storage
throw new NotImplementedException();
}
}
ПОКО, который работает:
public class someclass {
public virtual string id {get;set;}
[EncryptedDbString]
public virtual string abc {get;set;}
}
ПОКО, которая не:
public class otherclass {
public virtual string id {get;set;}
[EncryptedDbString]
public virtual Guid def {get;set;}
}
Это все automapped с Fluent.
Оба типа и тип строки являются nvarchar (500) в базе данных SQL.
Как уже упоминалось, первый ПОКО работает отлично и шифрует/расшифровывает, как и ожидалось, но второй ПОКО терпит неудачу, и это то, что я вижу в моих журналах:
NHibernate.Tuple.Entity.PocoEntityTuplizer.SetPropertyValuesWithOptimizer (Object объект, Object [] значения) { «Invalid Cast (проверить отображение для несовпадения типа недвижимости); сеттер OtherClass»}
Обратите внимание, что второй объект POCO прекрасно работает с nHib, если я удалю EncryptedDbString атрибут объявления, т.е. не имеет проблем с сохранением Guid на nvarchar.
Очевидно, проблема заключается в том, что это руководство, поскольку строковый регистр работает, но Я хочу, чтобы он хранился в качестве указателя не в строке в коде, и я не вижу здесь точки сбоя.
Похоже, что мне не хватает чего-то маленького. Наверное, я что-то пропустил с помощью дженериков, но я нашел только фрагменты кода, а не полный пример.
EDIT:
нормально, так что я понял, это я думаю, что это произошло потому, что
Get(IDataReader rs, int index)
не возвращает объект Guid.
поэтому, я думаю, вы можете сериализовать/десериализовать в методах Get/Set EncryptedStringType, например. в Get() можно изменить на:
if (typeof(T) == typeof(string))
return decrypted;
var obj = JsonConvert.DeserializeObject(decrypted);
return obj;
, но это кажется ужасным, особенно если у вас есть существующие данные по миграции.
Я не хочу хранить вещи как двоичные либо, так как команда хочет иметь возможность проверять/проверять/проверять вручную через SQL, какие столбцы зашифрованы (что очевидно с текстом, но не с двоичным).
Поле поддержки строк в моем POCO, которое преобразует Guid в строку и обратно через простые методы get/set, может быть лучшим вариантом, но я не знаю, как это сделать с автоматизацией через решение или как беспорядочно это?
Вы пробовали что-то вроде [этого] (http://stackoverflow.com/a/393787/497356)? Это может сработать. Также, что вы подразумеваете под «кажется ужасным, особенно если у вас есть данные для миграции?» –
На самом деле, вы правы. я думал, что я не хочу лишнего json в столбцах, когда у меня может быть только строка, но в любом случае, поскольку она зашифрована, это не делает такой большой разницы, поскольку она не будет отображаться вручную/запрашиваться в SQL-запросе анализатор в любом случае. спасибо за ваш комментарий, так как он устраняет необходимость в json и видит мой ответ: – jimasp
btw, если кто-либо читает это, захочет, например, хранить более сложные объекты как двоичные, а не строки, см. http://blog.muonlab.com/2010/04/20/encrypting-data-with-nhibernate/ – jimasp