Картинка блога

В одной из моих прошлых записей я рассказывал, что LINQ не совсем белый и пушистый, а иногда даже сильно ругается. Речь шла о методе SaveOrUpdate, сейчас я продолжу тему.
Прошлый пример похож на то, что по сути должен делать сам LINQ to MS SQL провайдер, естественно с кучей дополнительных деталей, на которых по всей видимости, часто возникают проблемы. Недостаток такого решения в том, что из него сложно сделать универсальный метод, так как неизбежно нужно сделать предварительную выборку по какому-либо ключу.

var originalEntity = dc.GetTable().Where(x => x.id== newEntity.id).SingleOrDefault();

Помочь может интерфейс. В таком случае, имя первичного ключа должно быть одинаковым.

Один мой коллега, надеюсь уже друг, разрешил опубликовать на блоге его реализацию расширения на class Table. Этот подход не требует никаких интерфейсов, а делает выборку с помощью простого SQL запроса. Никаких блужданий по деревьям выражений, или исправлений провайдера, жестко и эффективно. Вот код метода:

public static void InsertOrUpdateOnSubmit(this Table table, T entity)
where T : class
{
Dictionary primaryKeys = new Dictionary();

foreach (var property in entity.GetType().GetProperties())
foreach (ColumnAttribute ca in property.GetCustomAttributes(typeof(ColumnAttribute), false))
if (ca.IsPrimaryKey)
primaryKeys.Add(property.Name, property.GetValue(entity, null));

string tableName;
object[] tempAttributes = entity.GetType().GetCustomAttributes(typeof(TableAttribute), true);

if (tempAttributes.Length > 0)
tableName = (tempAttributes[0] as TableAttribute).Name;
else
throw new ArgumentException("Entity is not mapped to table");

string command = "SELECT * FROM " + tableName + " WHERE ";
int count = 0;
bool first = true;
foreach (var primaryKey in primaryKeys)
{
if (!first) command += " AND "; else first = false;
command += primaryKey.Key + " = {" + count++ + "}";
}

var originalEntity = table.Context.ExecuteQuery(command, primaryKeys.Values.ToArray()).SingleOrDefault();

if (originalEntity != null)
foreach (var property in entity.GetType().GetProperties())
{
PropertyInfo orignProperty = originalEntity.GetType().GetProperty(property.Name);
orignProperty.SetValue(originalEntity, property.GetValue(entity, null), null);
}
else
table.InsertOnSubmit(entity);
}

Спасибо Владимиру Калошину за код.

Метки:, ,

2 комментария в “LINQ Insert or Update еще одно решение.”

  1. Спасибо конечно, но а таком виде пример совершенно не читабелен,пойду искать дальше

  2. А скопировать в удобный для себя редактор религия не позволяет?