LINQ to Entity Změna Subjektu za Běhu

0

Otázka

Mám otázku. Mám dbContext, že má 200+ tříd, které představují všechny tabulky v databázi. Všechny tabulky stejný formát. Je možné dynamicky měnit kód za běhu, a to následujícím způsobem?

var coffeeList = new ObservableCollection<GenericCoffeeList>();
var query = (from c in ctxCoin.Coffee1
             select new GenericCoffeeList { CoffeeCatalogId = c.Id, Name = c.Name, Type = c.Type })
             .ToList();

foreach (var c in query)
{
    coinList.Add(c);
}

Zde je další typ entity, který je téměř stejný. Jediná změna je účetní jednotka

var coffeeList = new ObservableCollection<GenericCoffeeList>();

var query = (from c in ctxCoin.Coffee2
             select new GenericCoffeeList { CoffeeCatalogId = c.Id, Name = c.Name, Type = c.Type })
             .ToList();

foreach (var c in query)
{
    coinList.Add(c);
}

Existuje způsob, jak změnit účetní jednotky za běhu, nebo budu muset zákoníku každá účetní jednotka? Díky za jakýkoliv směr na tuto otázku.

c# dbcontext dynamic entity
2021-11-17 02:18:10
4
0

To by mělo fungovat pro EF6, ale byl jsem testování na EFCore.

Udělal jsem něco poněkud podobné s tím, když jsem potřeboval upravit všechny DbSets, které implementují určité rozhraní.

Máte dvě možnosti pro vaši situaci. Od všech vašich model typy nemají společný základní typ (jiné než object), můžete refaktorovat ty generované třídy extrahovat společné vlastnosti základní třídy ( Id, Namea Type vlastnosti).

Tady předpokládám, že vaše Coffee1 a Coffee2 tabulky jen typ entity Coffee1 a Coffee2 resp.

Možnost 1:

Refaktorovat tříd a extrakt tyto společné vlastnosti

public partial class Coffee1 : BaseCoffee {}
public partial class Coffee2 : BaseCoffee {}
public abstract class BaseCoffee
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string Type { get; set; }
}

pak se váš dotaz bude vypadat takto

var dbSets = ctxCoin.GetType().GetProperties()
    .Where(p => p.PropertyType.IsAssignableTo(typeof(IQueryable<BaseCoffee>)))
    .Select(set => set.GetValue(ctxCoin))
    .Cast<IQueryable<BaseCoffee>>();

var coffeeList = new ObservableCollection<GenericCoffeeList>();

foreach (var coffee in dbSets)
{
    var query = coffee.Select(c => new GenericCoffeeList { CoffeeCatalogId = c.Id, Name = c.Name, Type = c.Type });

    foreach (var c in query)
    {
        coffeeList.Add(c);
    }
}

Tato možnost je mnohem více typů-bezpečné a méně náchylné k chybám.

Možnost 2:

Použití reflexe IQueryable<object>

Udržujte své modely stejné a použít toto:

var dbSets = ctxCoin.GetType().GetProperties()
    .Where(p => p.PropertyType.IsAssignableTo(typeof(IQueryable<object>)))
    .Select(set => set.GetValue(ctxCoin))
    .Cast<IQueryable<object>>();

var coffeeList = new ObservableCollection<GenericCoffeeList>();

foreach (var queryableObject in dbSets)
{
    var query = queryableObject.Select(GenerateGenericCoffee);

    foreach (var c in query)
    {
        coffeeList.Add(c);
    }
}

Na GenerateGenericCoffee pomocník metoda

GenericCoffeeList GenerateGenericCoffee(object coffeeObject)
{
    var objType = coffeeObject.GetType();

    return new GenericCoffeeList
    {
        CoffeeCatalogId = GetProperty<int>("Id"),
        Name = GetProperty<string>("Name"),
        Type = GetProperty<string>("Type"),
    };

    T GetProperty<T>(string name)
    {
        return (T)objType.GetProperty(name).GetValue(coffeeObject);
    }
}

Pokud všechny své modely obsahují Id, Namea Typebudeš v pohodě , jinak budete muset zkontrolovat tyto vlastnosti existují první před provedením GenericCoffeeList položka.

2021-11-18 00:47:02

Hanku, Díky za kód. Otázka, odkud berete BaseCoffee?
Bryan K

Na DbSets na kontextu ctxCoin, dělat všechny typ argumentů na ty, mají stejné základní třídy nebo jen náhodou mají stejné vlastnosti? tedy máte DbSet<Class1> Coffee1 { get; set; } a DbSet<Class2> Coffee2 { get; set; }a Class1 a Class2 oba mají základní třídy BaseCoffee s vlastnostmi Id, Namea Type.
Hank McCord

Hanku, já jsem použil enitity framework pro generování class soubory nesdílejí základní třídy. Rámec vytváří dbContext nazývá CoffeeCatalogContext. Já ji použít pro přístup k částečné třídy vytvořené rámce. Jsem také pomocí EF Core
Bryan K

@BryanK přepsal jsem svou odpověď, aby vám více možností, které odrážejí vaši situaci. Doufejme, že to pomáhá!
Hank McCord

Hanku. Děkuji za kód. Nemám methos IsAssignableTo. Moje aplikace je blazor a c#, entity framework core. Z toho, co můžu říct IsAssignableTo je .čistá metoda.
Bryan K

@BryanK je novější .NET 5 a 6 pohodlí metoda. Můžete použít své dvojče typeof(IQueryable<object>).IsAssignableFrom(p.PropertyType) místo. Ten má k dispozici od .NETFramework.
Hank McCord

Dám to zkusit. Díky za všechny vaše pomoc.
Bryan K

Hanku, já nejsem dostat žádné výsledky z této části kódu a nemůžu přijít na to, proč. var dbSets = ctxCoin.GetType().GetProperties() .Where(p => p.PropertyType.IsAssignableFrom(typeof(IQueryable<object>))) .Vyberte(nastavení => nastavení.GetValue(ctxCoin)) .Obsazení<IQueryable<object>>();
Bryan K
0

Myslím, že vytvoření genetické třídy na dotaz. Při změně Objektu(TEntity), dotaz proveden pro Objekt(TEntity).

public class QueryRepo<TEntity> where TEntity : class
{
    private readonly ctxCoin;
    public QueryRepo(){
        ctxCoin = new CtxCoin();
    }

    public IEnumerable<GenericCoffeeList> GetCoffeeList()
    {
        var entity = ctxCoin.Set<TEntity>();
        return (from c in entity
            select new GenericCoffeeList
            {
                CoffeeCatalogId = c.Id,
                Name = c.Name,
                Type = c.Type
            }).ToList();
    }
}
2021-11-17 07:31:06

Prosím, test kód před odesláním.
Gert Arnold

Díky jste se Gerta. Bych mohl chybět "něco". Napsal jsem bez ide.
karagoz

Hlavně kosmetické změny. Stále není kompilace.
Gert Arnold

Řekl jsem to nepsal s compiler. Myslíte si, že tento blok kódu dává smysl ?
karagoz

Pak napište to v IDE a vyzkoušet si to. Všichni bychom měli dělat, že (a příliš málo lidí, bohužel). Pokud to nebude kompilovat to nedává smysl.
Gert Arnold
0

Já osobně bych se pokusit pomocí obecné metody s labda, který se používá k převedení různých druhů Kávy do GenericCoffeeList.

public IEnumerable<GenericCoffeeList> GetCoffeeList<TCoffee>(Func<TCoffee, GenericCoffeeList> toGenericCoffeeList)
{
    return ctxCoin.Set<TCoffee>()
        .Select(coffee => toGenericCoffeeList(coffee)
        .ToList();
}

To dělají tímto způsobem, snižuje množství kódu potřebné a jediná věc, která musí být duplciated je funkce, které je předán jako toGenericCoffeeList ale také nevyžaduje refactoring 200+ třídy, implementovat rozhraní.

Tento přístup může být upraven v závislosti na tom, co je třeba udělat (nejsem si přesně jistý, co vaše metoda má dělat, protože coffeeList je nikdy použity, a coinList nikdy prohlásil,)

2021-12-15 12:00:08

Nannana, může TCoffee být řetězec, který je předán v?
Bryan K

Ne, to musí být typ, který chcete dotaz - může být použit jako GetCoffeeList<Coffee1>(coffee1 => new GenericCoffeeList { CoffeeCatalogId = coffee1 .Id, Name = coffee1 .Name, Type = coffee1 .Type })
Nannanas

To, co jsem si myslel. To, co se snažím vyhnout. Mám 200+ TEntites tak hledám řešení, kde nemám pevný kód každé z nich.
Bryan K
0

Můžete map jednoho Typu na jiný pomocí mapování oblastech, jako je tato:

public static Expression<Func<T, R>> MapFields<T, R>(IDictionary<string, string> fieldNamesMapping) 
            where R: new()
{
    var parameter = Expression.Parameter(typeof(T), "o");  
             
    return Expression.Lambda<Func<T, R>>(
        Expression.MemberInit(
            Expression.New(typeof(R)), 
            GetMemberBindings<T,R>(fieldNamesMapping, parameter)), 
        parameter);
}
      

private static IEnumerable<MemberBinding> GetMemberBindings<T,R>(IDictionary<string, string> fieldNamesMapping,
    ParameterExpression parameter) 
        => fieldNamesMapping
            .Select(o => (MemberBinding)Expression.Bind(
                typeof(R).GetProperty(o.Value) ?? throw new InvalidOperationException(), 
                Expression.Property(parameter, typeof(T).GetProperty(o.Key) ?? throw new InvalidOperationException())));

Tento kód předpokládá, že druhy mají vlastnosti s podobnými typy, ale různá jména. Tedy Slovník s odpovídající filednames.

Pokud pole náhodou mají stejné názvy můžete samozřejmě odvodit vlastnosti pomocí reflexe.

Použití je tak jako:

var toBeMapped = new List<FooA> {
                new FooA {A = 1, B = 2, C = 3},
                new FooA {A = 4, B = 5, C = 6},
                new FooA {A = 7, B = 8, C = 9},
                new FooA {A = 10, B = 11, C = 12}
            };

            var result = toBeMapped.AsQueryable().Select(
                MemberBindingExpressions.MapFields<FooA, FooB>(
                    new Dictionary<string, string> {["A"] = "A", ["B"] = "E"})).ToList();

            result[0].Should().Be(new FooB {A = 1, E = 2});
            result[3].Should().Be(new FooB { A = 10, E = 11 });
2021-12-15 14:33:41

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................