Using a string to access a table through DbContext - c#

I want to pass a string in the LINQ query.
string TableName = "db.Countries";
var ActualData = (from n in TableName
where n.Record_Instance >= 0
select n).OrderBy(primaryColumn);
My aim behind this is; I want to put the query in a method and call it whenever I need it. Basically changing the TableName and passing it as a parameter on function call.
Is there a way to do this?
Update :
Workaround :
var TableName = db.Countries;
GetConditionaldata(TableName,..);
private object GetConditionaldata( DbSet<Country> TableName, ..)
{
var ConditionalData = (from n in TableName
where n.Record_Instance >= 0
select n).OrderBy(primaryColumn);
var count = ConditionalData.Count();
var countries = ConditionalData.Skip(jtStartIndex).Take(jtPageSize);
return countries;
}
But Here, I want have to again specify DbSet<Country> as the parameter type. If I can at least find a way to get a Generic Dbset<> Which I can pass on as parameter type for my tableName, then my problem would be solved.

Assuming you have multiple entities containing the same property that you want to execute the same query on, then you can introduce an interface:
public interface IInstanceRecord
{
int Record_Instance { get; set; }
}
Then apply it to your entities in partial classes (or directly if using Code First):
public partial class Country : IInstanceRecord { }
public partial class Foo : IInstanceRecord { }
public partial class Bar : IInstanceRecord { }
Now you can make your method generic, and add a constraint that the generic types it operates on must implement IInstanceRecord:
public IQueryable<T> GetConditionalData<T>(IQueryable<T> dbSet, ...)
where T : IInstanceRecord
{
var conditionalData = (from n in dbSet
where n.Record_Instance >= 0
select n).OrderBy(primaryColumn);
var count = conditionalData.Count();
var filteredData = conditionalData.Skip(jtStartIndex).Take(jtPageSize);
return filteredData;
}
And call it with whatever DbSet<T> (or other IQueryable<T>) you want, as long as T : IInstanceRecord:
var filteredCountries = GetConditionalData(dbContext.Countries);
var filteredFoos = GetConditionalData(dbContext.Foos);
var filteredBars = GetConditionalData(dbContext.Bars);

Related

C# how to return 1 row from List<T> object passed as parameter

I need to return one row of List from my function Selectus.
So I pass to the function Selectus object that reflects database table fields and I need to return one row which match the parameter looking_for:
public static List<T> Selectus<T>(string looking_for)
{
//all select data
var db = OrmLiteBaza().Open();//opening database
var select_all_list = db.Select<T>();//getting all data for <T> object works fine
db.Dispose();
//try to select one row - here I have trouble:
var prop = typeof(T).GetProperties();//properties of passed <T> object
var list_selected_record = from records in select_all_list where prop[1].Name == looking_for select records;//tryin to select one record from <T> object as in looking_for variable
return list_selected_record.ToList();//here one record should be returned
}
I do not know how to select one row from the list assuming that T parameter is vary. In SelectusT> method I want to pass as T different objects which reflect fields in database table rather than creatinig separate methods for each select. e.g. call Selectus, where object passed is public class ProductCodes { public int ID { get; set; } public string SapIndex { get; set; } public string SapName { get; set; } }. Then I want to call another Selectus<ProductTypes> for another table etc... So I want to write generic/overall method and use it universally for all types of my objects which reflects the fields of few database tables. The SapIndex property is always in the same place of all objects...
Using prop[1] is incredibly fragile. Who says that the property you're currently interested in is always going to be in second place? What if someone adds another property tomorrow? What if not every T that you use have the same property in the second place on its list of properties? It is quite unclear what your actual goal is here and why you've taken the reflection route.
You would be better off using inheritance or interface implementation here. I'm going to use an interface in this answer, but either would work.
For the sake of clarity, let's assume there is a Code field in all your possible lists, and this is the property you're trying to match with.
Define a reusable interface:
public interface ICodeEntity
{
string Code { get; }
}
Apply your interface to all of the classes that you intend to use for your Selectus method.
public class Person : ICodeEntity
{
public string Code { get; set; }
// And other properties
}
public class Document : ICodeEntity
{
public string Code { get; set; }
// And other properties
}
Add a generic type constraint that limits the use of T only to types that implement your interface.
public static List<T> Selectus<T>(string code)
where T : ICodeEntity
You can now write your code in a way that it relies on the type in question having a Code property, and the compiler will help enforce it.
var db = OrmLiteBaza().Open();
var list = db.Select<T>().ToList();
db.Dispose();
return list.Where(item => item.Code == code).ToList();
Usage examples:
List<Person> peopleWithCodeABC = Selectus<Person>("ABC");
List<Person> documentsWithCodeXYZ = Selectus<Document>("XYZ");
// This will fail if Animal does not implement ICodeEntity
var compilerError = Selectus<Animal>("ABC");
I might not understand fully what you want, but instead of string looking_for you could pass in a Func<,> delegate which acts as a selector.
Something like:
public static List<TField> Selectus<T, TField>(Func<T, TField> selector)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
var list_selected_record = select_all_list.Select(selector); // 'using System.Linq;'
return list_selected_record.ToList();
}
Then I believe it could be called like this:
var list_one = Selectus((ProductCodes x) => x.SapIndex);
var list_two = Selectus((ProductTypes x) => x.SapIndex);
var list_three = Selectus((ProductCodes x) => x.SapName);
With this syntax I leave out the <ProductCodes, string> generic arguments to the method since they can be inferred.
Hmm, maybe you want it in the opposite dimension. You could do:
public static List<T> Selectus<T>(Func<T, bool> predicate)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
var list_selected_record = select_all_list.Where(predicate); // 'using System.Linq;'
return list_selected_record.ToList();
}
with:
var list_one = Selectus((ProductCodes x) => x.SapIndex == "ABC");
var list_two = Selectus((ProductTypes x) => x.SapIndex == "ABC");
var list_three = Selectus((ProductCodes x) => x.SapName == "DaName");
or:
var list_one = Selectus<ProductCodes>(x => x.SapIndex == "ABC");
var list_two = Selectus<ProductTypes>(x => x.SapIndex == "ABC");
var list_three = Selectus<ProductCodes>(x => x.SapName == "DaName");
But if it is going to always be the "same" property, like always x.SapIndex (but for different types of x), then Flater's answer looks good.
Otherwise, if you insist, your reflection approach should be possible. Use propety's name, not its index! Let me try:
public static List<T> Selectus<T>(string looking_for)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
const string prop_name = "SapIndex";
var prop = typeof(T).GetProperty(prop_name); // can blow up for bad T
var list_selected_record = select_all_list
.Where(x => (string)(prop.GetValue(x)) == looking_for); // 'using System.Linq;'
return list_selected_record.ToList();
}
with:
var list_one = Selectus<ProductCodes>("ABC");
var list_two = Selectus<ProductTypes>("ABC");
you can change code to return just one element
public static T Selectus<T>(string looking_for)
{
//all select data
var db = OrmLiteBaza().Open();//opening database
var select_all_list = db.Select<T>();//getting all data for <T> object works fine
db.Dispose();
//try to select one row - here I have trouble:
var prop = typeof(T).GetProperties();//properties of passed <T> object
var list_selected_record = from records in select_all_list where prop[1].Name == looking_for select records;//tryin to select one record from <T> object as in looking_for variable
return list_selected_record.FirstOrDefault();//here one record should be returned
}

DbSet variable table name

I am writing an application where I need to abstract the DbSet table name.
Instead of calling _db.Activities.ToList() (where Activity is a table in Sql) the code below will work for any variable table input.
Now I wanted to use .Where(),.OrderBy(),.FromSqlRaw() and other methods on top of the existing code.
How can I write _db.Activities.FromSqlRaw(...) for example, with a variable table name, just like it is doing for the GetAll method.
This is my DbSet for Activity
public virtual DbSet<Activity> Activities { get; set; } = null!;
This is the method to get all records from a variable table
public dynamic GetAll(string Table)
{
var curEntityPI = _db.GetType().GetProperty(Table);
var curEntityType = curEntityPI.PropertyType.GetGenericArguments().First();
// Getting Set<T> method
var method = _db.GetType().GetMember("Set").Cast<MethodInfo>().Where(x => x.IsGenericMethodDefinition).FirstOrDefault();
// Making Set<SomeRealCrmObject>() method
var genericMethod = method.MakeGenericMethod(curEntityType);
// invoking Setmethod into invokeSet
dynamic invokeSet = genericMethod.Invoke(_db, null);
// invoking ToList method from Set<> invokeSet
return Enumerable.ToList(invokeSet);
}
The general idea comes from this post
reflection-linq-dbset
Define return type of method as List< dynamic> instead of dynamic
public List<dynamic> GetAll(string Table)
{
//your code...
return Enumerable.ToList(invokeSet);
}
Activity Class:
public class Activity
{
public int Field1 { get; set; }
public string Field2 { get; set; }
}
So, you can use all methods of List type
var activityList = GetAll("Activities");
var filteredList = activities.Where(x => x.Field1 > 1);
var orderedList = filteredList.OrderBy(x => x.Field2);

Find Max(Id) of DbSet<T> where T is unknown

How do I find the biggest Id of a DbSet.Set<T>()?
Note: not DbSet<TEntity>.
I don't know the type at runtime.
Context: I have 20 tables/entities, which I'm using a generic method to do processing.
The process involves looking up the biggest Id of that table/entity and comparing it with the record at hand.
If the record's id is bigger than the database's, than it would be inserted into the database.
So far I've tried using reflection:
DbSet<T> table = DbContext.Set<T>();
var lastRecord = table.LastOrDefault(); // throws not supported error
var idProperty = lastRecord.GetType().GetProperties()
.FirstOrDefault(p => p.Name.Equals("Id");
int maxId = (int)idProperty.GetValue(lastRecord);
I've also tried using an interface cast:
interface ICommonEntity
{ // this interface allows the generic method
string StringId { get;} // to know how to handle entity Id's of
int? IntId { get; } // different types (string vs int).
}
var whatever = table.OrderByDescending(e => (e as ICommonEntity).IntId).FirstOrDefault();
int maxId = (whatever as ICommonEntity).IntId ?? 0;
But the above yields the following error:
The 'TypeAs' expression with an input of type xx is not supported. and a check of type yy. Only entity types and complex types are supported in LINQ to Entities queries
Additional data: All my entities have the column/property Id of type int.
Web searches that I've done mainly point to solutions that the type is known e.g. TEntity, db.Users.xxx() etc..
Update
In response to Ian's answer, I can't use Id directly. Why?
One of my entity has a field named Id, but is of type string.
class EntityStringId : ICommonEntity
{
public string Id { get; set; }
public string StringId => Id;
public int? IntId => null;
}
class EntityIntId : ICommonEntity
{
public int Id { get; set; }
public string StringId => null;
public int? IntId => Id;
}
And if I try to use IntId for ordering,
private void SomeMethod<T>(string file)
//where T : class // original
//where T : ICommonEntity // cannot. DbContext.Set<T>(); requires class
where T : class, ICommonEntity // throws exception
{
var table_T = DbContext.Set<T>();
var maxId = table_T.Max(e => e.IntId); // throws exception ↓
}
The specified type member 'IntId' is not supported in LINQ to Entities.
Only initializers, entity members, and entity navigation properties are supported.
For a better picture, my method's logic:
private void ProcessCsvToDb<T>(
DbSet<T> table,
T csvRecord) where T : class
{
var iRecord = csvRecord as ICommonEntity;
T dbRecord = null;
if (!string.IsNullOrEmpty(iRecord.StringId))
{
dbRecord = table.Find(iRecord.StringId);
}
else if (iRecord.IntId != null)
{
dbRecord = table.Find(iRecord.IntId);
}
}
In order to do this without a base class/interface, you will need to manually compose the expression:
public static IOrderedQueryable<int> OrderById(Type entityType)
{
var dbSet = context.Set(entityType);
var item = Expression.Parameter(entityType, "item");
var property = Expression.Property(item, "Id");
var lambda = Expression.Lambda<Func<T, int>>(property, item);
// the above generates:
// item => item.Id
return dbSet.OrderByDescending(lambda);
}
You can build expression to sort by Id, but DynamicQueryable class does it for you:
DbSet<T> table = assignFromSomeWhere();
var maxId = table.OrderBy("Id desc").FirstOrDefault();
DynamicQueryable also gives you different extension methods (dynamic Where, Select). Obviously it is bigger satisfaction to build expressions on your own, but sometimes it is very complicated and this library helps a lot.
If you have an interface, as discussed in comments, is there any reason you can't do this to avoid the cast:
public static int? GetMaxId<T>(DBSet<T> dbSet)
where T : ICommonEntity
{
return dbSet.OrderByDescending(e => e.Id).FirstOrDefault();
}

Creating common class objects based on class name and use it

I have the same code logic used across different class objects.
For ex:
var matchingTypes = from matchType in order.Contacts
select matchType;
var matchingTypes = from matchType in customer.Contacts
select matchType;
Instead of writing duplicate lines of code, i would like to pass order, customer class names and get Contacts through it, so that the above code will look like (we are using LINQ in our code)
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
The stuff i tried is passed an object parameter
GetData(object objectElement) // method consuming an object parameter.
var objectOrder= objectElement as Orders;
var objectCustomer= objectElement as Customers;
if(objectOrder!=null)
{
objectElement = (Orders) objectOrder; //type
}
if(objectCustomer !=null)
{
objectElement = (Customers) objectCustomer;
}
By doing so, i am repeating my code, which i would like to avoid, any suggestions/ideas? thanks.
I would like to use objectElement and assign only once, so that i can call like this as shown below
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
An interface would be the preferred way to do this, but you could also use dynamic to duck type a method:
public IEnumerable<Contact> GetContacts(dynamic yourObject)
{
return yourObject.Contacts;
}
Note this will not give you a compile error if you call it with something that doesn't have a property called Contacts of type IEnumerable<Contact> but will instead give you a runtime error.
Or you don't even actually need a method, you could just do this:
var matchedTypes = ((dynamic)yourObject).Contacts as IEnumerable<Contact>;
Interfaces would be a safer bet, but are a little tricky with generate entity framework classes. But you can do them becuase they are generated as partial classes. So you can do something like this:
public interface IHaveContacts
{
public IEnumerable<Contact> Contacts { get; }
}
and then:
public partial class Orders : IHaveContacts
{
// should need to do anything since the auto-genrated Contacts property
// will satisfy the interface
}
public partial class Customers : IHaveContacts
{
// ditto
}
And now you can do:
var matchedTypes = ((IHaveContacts)yourObject).Contacts;
Or, if you really, really must (which you don't):
var matchedTypes = from matchType in ((IHaveContacts)yourObject).Contacts
select matchType;
Create an interface IContactsContainer:
public interface IContactsContainer
{
public YourContactType Contacts{get;set;}
}
Then your customer and order classes can implement it:
public class Customers : IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
public class Orders: IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
After that in your method you can use:
IContactsContainer objectElement = yourOrderObject;

Casting to a derived type in a LINQ to Entities query with Table Per Hierarchy inheritance

I have a LINQ to entities model with Table Per Hierarchy inheritance. I have a query over the base type, and I want to do specific type-dependent logic. For example:
IQueryable<BaseType> base = ...
// this works fine
var result = base.Select(b => b is DerivedType1 ? 1 : 2).ToList();
// this doesn't compile to SQL
var result2 = base.Select(b => b is DerivedType1 ? ((DerivedType1)b).DerivedProperty : null).ToList();
Is there any way to do something like this without processing IQueryables of each derived type separately:
// I'd rather not do this:
var resultA = base.OfType<DerivedType1>().Select(d => d.DerivedProperty);
var resultB = base.OfType<DerivedType2>().Select(d => default(int?));
var result = resultA.Concat(resultB).ToList();
Direct casting to an entity type like (DerivedType1)b isn't supported with LINQ-to-Entities but the as operator (b as DerivedType1) is, hence you could try:
var result2 = base
.Select(b => b is DerivedType1
? (b as DerivedType1).DerivedProperty
: null)
.ToList();
OfType<DerivedType1>()
will return an IEnumerable, if possible, try to change to base-type to IEnumerable instead of IQueryable, you might en up in some SQL restrictions when using IQueryable.
That is of course if you are not actually quering a database?
You can use EntityFramework.Extended to improve the performance of the query instead of doing 2 round trips to DB.
var resultA = base.OfType<DerivedType1>().Select(d => d.DerivedProperty).Future();
var resultB = base.OfType<DerivedType2>().Select(d => default(int?)).Future();
var result = resultA.Concat(resultB).ToList();
In this case only one round trip to bd is executed.
This framework is very useful for many other things int EF
You could have a method on your base type that's overridden in your derived types to provide the relevant property value.
public class MyBaseClass
{
public virtual int GetSomething()
{
throw new NotImplementedException();
}
}
public class MyDerivedClass1 : MyBaseClass
{
public int SomeProperty { get; set; }
public override int GetSomething()
{
return this.SomeProperty;
}
}
public class MyDerivedClass2 : MyBaseClass
{
public int SomeOtherProperty { get; set; }
public override int GetSomething()
{
return this.SomeOtherProperty;
}
}
Then you could:
var result = base.Select(b => b.GetSomething()).ToList();
Try this, I have never done anything with needing to do this kind of this but this should do it. Also if you use base, first of all don't because it is a keyword but if you must, use #base the # in front of the name denotes that it is not used as a keyword.
var resultA = base.Select(aVar =>
(aVar is DerivedType1) ?
(DerivedType)(((DerivedType1)aVar).DerivedProperty)
:
(DerivedType)(default(int?))
).ToList();

Categories