#.net #orm #repository #linq2db
#.net #орм #репозиторий #linq2db #orm
Вопрос:
Я хочу использовать dynamic, чтобы иметь возможность выбирать, какие столбцы определять, и те, которые я хочу разрешить базе данных устанавливать DEFAULT
значение. Есть ли способ вставить dynamic
в таблицу и вернуть Id
?
Я пробовал различные перегрузки как на DataConnection
, так и ITable<>
, но единственный результат, которого я смог добиться, — это получить количество затронутых строк.
Это мой код:
Схема таблицы персон
CREATE TABLE [dbo].[Person] (
[Id] BIGINT IDENTITY (1, 1) NOT NULL,
[Name] VARCHAR (50) NOT NULL,
[Surname] VARCHAR (50) NOT NULL,
[BirthDate] DATE DEFAULT (getdate()) NOT NULL
);
Консольное приложение .NET Core
public class Person
{
public uint Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime BirthDate { get; set; }
}
public class PeopleDataConnection : DataConnection
{
public PeopleDataConnection(string connectionString)
: base(ProviderName.SqlServer, connectionString)
{ }
public ITable<Person> People => this.GetTable<Person>();
}
class Program
{
static async Task Main(string[] args)
{
await using (var db = new PeopleDataConnection("Server=DESKTOP-I41VSUN;integrated Security=SSPI;Database=MotoGPRiders;"))
{
var dynamicPerson = new { Name = "Cal", Surname = "Crutchlow", BirthDate = new DateTime(1985, 10, 29) };
var person_without_id = new Person { Name = "Valentino", Surname = "Rossi", BirthDate = new DateTime(1979, 2, 16) };
var affectedRowsCount = await db.InsertAsync(dynamicPerson, nameof(Person));
affectedRowsCount = await db.People
.Value(x => x.Name, person_without_id.Name)
.Value(x => x.Surname, person_without_id.Surname)
.Value(x => x.BirthDate, person_without_id.BirthDate)
.InsertAsync();
}
Console.ReadLine();
}
}
Первая вставка выполняет задание, но не может вернуть Id
, вторая позволяет мне выбирать столбцы, но не динамически.
Есть ли способ добиться этого? Заранее спасибо!
Ответ №1:
Вы можете получить значение идентификатора с помощью InsertWithInt64IdentityAsync
функции. Для такой вставки много перегрузок:
var insertedId = await db.People
.Value(x => x.Name, person_without_id.Name)
.Value(x => x.Surname, person_without_id.Surname)
.Value(x => x.BirthDate, person_without_id.BirthDate)
.InsertWithInt64IdentityAsync();
Также вы можете отфильтровать свойства, которые должны быть вставлены через перегрузку, которая имеет columnFilter
параметр:
var insertedId = await db.InsertAsync(person,
e => e.MemberName.In("Name", "Surname", "BirthDate"));
Для варианта с анонимным классом вам необходимо создать свою собственную функцию, которая генерирует вызовы посредством отражения с использованием Value.Value.Value
InsertWithInt64IdentityAsync
вызовов:
public static class DynamicExtensions
{
public static IValueInsertable<T> GenerateInsertable<T>(this ITable<T> table, object obj)
{
var dynamicAccessor = TypeAccessor.GetAccessor(obj.GetType());
var accessor = TypeAccessor.GetAccessor<T>();
var objValue = Expression.Constant(obj);
IValueInsertable<T> insertable = null;
foreach (var dynamicMember in dynamicAccessor.Members)
{
var found = accessor.Members.Find(m => m.Name == dynamicMember.Name);
if (found == null)
continue;
var sourceParam = Expression.Parameter(typeof(T), "e");
var property = Expression.Lambda(Expression.MakeMemberAccess(sourceParam, found.MemberInfo),
sourceParam);
Expression value = Expression.MakeMemberAccess(objValue, dynamicMember.MemberInfo);
if (value.Type != found.Type)
value = Expression.Convert(value, found.Type);
value = Expression.Lambda(value);
if (insertable == null)
{
var method = Methods.LinqToDB.Insert.T.ValueExpression.MakeGenericMethod(typeof(T), found.Type);
insertable = (IValueInsertable<T>)method.Invoke(null, new object[] { table, property, value });
}
else
{
var method = Methods.LinqToDB.Insert.VI.ValueExpression.MakeGenericMethod(typeof(T), found.Type);
insertable = (IValueInsertable<T>)method.Invoke(null, new object[] { insertable, property, value });
}
}
return insertable;
}
public static long? InsertWithIdentityDynamic<T>(this ITable<T> table, object obj)
{
var insertable = GenerateInsertable(table, obj);
if (insertable == null)
return null;
return insertable.InsertWithInt64Identity();
}
public static async Task<long?> InsertWithIdentityDynamicAsync<T>(this ITable<T> table, object obj, CancellationToken cancellationToken = default)
{
var insertable = GenerateInsertable(table, obj);
if (insertable == null)
return null;
return await insertable.InsertWithInt64IdentityAsync(cancellationToken);
}
}
И использование:
var insertedId = await db.GetTable<Person>()
.InsertWithIdentityDynamicAsync(dynamicPerson);