How to apply the same query to different entities? - c#

So, I'm beggining to use EF, and I'm developing an application using it as ORM. The thing is I haven't had much time to dig into the documentation (I Plan to, in due time)and I'm kind of lost in some things. For example, I have these two queries:
public static int GetNextPadlockNumber()
{
LockersDBEntities1 entities = new LockersDBEntities1();
var query = (from p in entities.PadLocks select p.PadlockNumber).DefaultIfEmpty(0).Max();
return (int)query + 1;
}
public static Data.PadLock GetPadLockByNumber(int number)
{
Data.LockersDBEntities1 entities = new LockersDBEntities1();
var query = (from p in entities.PadLocks where p.PadlockNumber == number select p).FirstOrDefault();
return query;
}
and
public static int GetNextLockerNumber()
{
LockersDBEntities1 entities = new LockersDBEntities1();
var query = (from l in entities.Lockers select l.LockerNumber).DefaultIfEmpty(0).Max();
return (int)query+1;
}
public static Data.Locker GetLockerByNumber(int number)
{
Data.LockersDBEntities1 entities = new LockersDBEntities1();
var query = (from l in entities.Lockers where l.LockerNumber == number select l).FirstOrDefault();
return query;
}
And the thing is They're Exactly the same query. Isn't there Any way to do this without having to specify that I want a locker or a padlock? Thanks in advance heroes.

You could have used the LockerNumber and PadlockNumber as Identity Autoincrement fields since that is what you are doing, and then named them the same (Id for instance).
And that way the need to "get next locker number" is no longer necessary since every new entity inserted will get the next available number and with a Repository pattern you could have those methods as common methods in the Base Repository class as something like this:
public IEntity GetEntityById(int number)
{
return ObjectSet.Single(x => x.Id == number);
}

One of the great things with EF is that you can do things like that. It's not trivial, and it will take some trial and error, but you can abstract a lot of the database complexities away.
Now, assuming that LockersDBEntities1 is a DbContext, you could something like this:
public static class LockersDBEntities1Extensions
{
public static int GetNextNumber<T>(
this LockersDBEntities1 context,
Expression<Func<T, int>> getNumberExpression)
{
var query = (from item in context.Set<T>
select getNumberExpression(item))
.DefaultIfEmpty(0)
.Max();
return (int)query + 1;
}
}
and use it like:
int nextPadlockNumber = new LockersDBEntities1()
.GetNextNumber<Padlock>(p => p.PadlockNumber)
and
int nextPadlockNumber = new LockersDBEntities1()
.GetNextNumber<Locker>(l => l.LockerNumber)
The getNumberExpression expression is needed because there is no common way to access the number across all entities. It might be overdesign, but if that is an issue I would do something like this:
//this should be a better name, to reflect the real scenarion
interface ILockNumberProvider
{
int Number {get; }
}
and implement that interface on Locker, Padlock and other classes that need to provide lock numbers. Then, in the method above the expression can be omitted, and a generic constraint can be used, like:
public static class LockersDBEntities1Extensions
{
public static int GetNextNumber<T>(this LockersDBEntities1 context)
where T:ILockNumberProvider
{
var query = (from item in context.Set<T>
select item.Number)
.DefaultIfEmpty(0)
.Max();
return (int)query + 1;
}
}

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
}

Combining Linq-Entity statements

I have 2 repositories, Member and Person. The Person Model contains a nullable reference property to a Member Model. The Member Model is defined in the Member Repository and I would like to put in place a pattern that ensures this stays that way. however, when I call the methods in the member repo from the person repo I get the
LINQ to Entities does not recognize the method 'System.Linq.IQueryable 1[...IMember] Get(..Entities,System.Linq.Expressions.Expression 1[System.Func`2[..tblMember,System.Boolean]])' method, and this method cannot be translated into a store expression."
While I understand this can be easily solved by putting .asEnumerable() then a second select there is a cost that means your doing 2 queries instead of one and you loose the ability to expose the method as awaitable. Below is the code I have removed a few non essential parts to clearify. I am not using lambda because I have not found a good way to say let in a lambda expression. My goal is person.Member would simply be a nested select. Also Note that the Member side of things is a very ugly database that I have not control over and these repos are being separated for a reason. Thanks in advance
public class MemberRepository : Interfaces.IRepository<IMemberBase, string>
{
private Data.LSAEntities entities { get; set; }
public MemberRepository(Data.LSAEntities entities)
{
this.entities = entities;
}
internal static IQueryable<IMember> Get(Data.LSAEntities entities, Expression<Func<tblMember, bool>> predicate)
{
return (from t in entities.tblMembers.Where(predicate)
let options = entities.tblDataOptions.Where(o => o.DataName == "MemberStatus")
select new Member()
{
MemberID = t.MemberID,
...
});
}
}
public class PersonRepository : IRepository<IPerson, int>
{
private Data.LSAEntities entities { get; set; }
public PersonRepository(Data.LSAEntities entities)
{
this.entities = entities;
}
public IQueryable<IPerson> Get(int key)
{
return (from p in entities.tblPersons
where p.PersonId == key
select new Person()
{
PersonId = p.PersonId,
...
Member = MemberRepository.Get(entities, m=> p.MemberId == m.MemberID).FirstOrDefault()
});
}
}
This may help you:
Given
var ans = from a in table
let b = a.TotalPrice / a.Quantity
where b > 500
select new {
PriceEa = b,
a.ID,
a.Description
};
translates to
var ans = table.Select(a => new { b = a.TotalPrice / a.Quantity, a })
.Where(ba => ba.b > 500)
.Select(ba => new {
PriceEa = ba.b,
ba.a.ID,
ba.a.Description
});
the let clause in query comprehension syntax in LINQ is translated to a Select adding a new field to hold the let value when using lambda syntax.

Is it possible to store, or pre-define a LINQ query for re-use?

I currently have a linq query that i use about 5 times within the same MVC class, is it possible to define the query somewhere within the page in the same way you can public const a string or an int, without having to create a method which calls the linq query?
i.e.
const LinqQuery myQuery = from cat in db.Categories where cat.CategoryID != null select cat;
...
public ActionResult Edit(long id = 0)
{
ViewBag.ParentCategoryID = myQuery;
...
}
public ActionResult Create()
{
ViewBag.ParentCategoryID = myQuery;
...
}
From what i can see, the only way is creating a method, but i would like to avoid it if there is a nicer way of doing things.
My crystal ball tells me that Linq queries are only executed when you iterate over the result so:
static List<int> list = new List<int> { 1, 2, 3 };
static IEnumerable<int> result = from i in list where i > 2 select i;
static void Main(string[] args)
{
Console.WriteLine(result.Sum()); // 3
list.Add(5);
Console.WriteLine(result.Sum()); // 8
}
MSDN Has an article on precompiled queries:
http://msdn.microsoft.com/en-us/library/bb399335.aspx
In your example it could look something like this:
public static readonly Func<MyContext, int, IQueryable<Category>>
myQuery = CompiledQuery.Compile((MyContext db, int categoryID) =>
from cat in db.Categories where cat.CategoryID == categoryID select cat);
I added readonly as it is going to be the closest you'll get to a constant.
You're in luck, sorta, While it's similar, you can declare a Func<> and call that. It looks cleaner / nicer than a method when you only have a very simple instruction you want to execute.
Here's sorta an example on their implementation (This is from a project where I had to use SetWindowPos multiple times along with some other stuff):
Func<Process, winPosData, bool> swp = (p, w) => SetWindowPos(p.MainWindowHandle, (IntPtr)w.hWndInsertAfter, w.x, w.y, w.cx, w.cy, w.uFlags);
Yes, just put it in the constructor (I assume the type of db.Catagories is Catagory)
public class ClassName
{
public ClassName()
{
db = //do whatever is needed to initialize the db context
myQuery = from cat in db.Categories where cat.CategoryID != null select cat;
}
DataSourceContext db;
IQueryable<Catagory> myQuery;
public ActionResult Edit(long id = 0)
{
ViewBag.ParentCategoryID = myQuery;
...
}
public ActionResult Create()
{
ViewBag.ParentCategoryID = myQuery;
...
}
}
This could also be done in the static constructor with static members if access to db is done in a thread safe manner (via internally inside DataSourceContext or by you in defensive coding)
However a better way would be to call a static function that returns the query you want and passing in the context of the database you want to connect to.
public static IQueryable<Catagory> NonNullCatagoriesQuery(DataSourceContext db)
{
return from cat in db.Categories where cat.CategoryID != null select cat;
}
Then in your code you just do
public ActionResult Edit(long id = 0)
{
ViewBag.ParentCategoryID = NonNullCatagoriesQuery(db);
...
}
public ActionResult Create()
{
ViewBag.ParentCategoryID = NonNullCatagoriesQuery(db);
...
}
You also could move the function in to a repository class that held the db context too so you would not need to pass it in, but you did not include in your code example how you got db.

Access to Model in Entity Framework

What is the problem of idea that we have a static property of our entity model like this?
public class Repository{
private static KiaNetEntities entities = null;
public static KiaNetEntities{
get{ return entities; }
}
static Repository(){
entities = new KiaNetDbEntities();
}
}
and use it like this:
public static Customers[] GetCustomers(){
var q = from c in KiaNetEntities.Customers where c.Activated select c;
return q.ToArray();
}
public static Customers[] AddToCustomerSalary(int customerId, decimal newValue){
var q = from c in KiaNetEntities.Customers
where c.Activated && c.ID == customerId
select c;
if(q.Count() > 0){
var customer = q.First();
customer.Salary += newValue;
KiaNetEntities.SaveChanges();
}
}
What is the problem? There are quite lot of them - some are described here and you can add one more - EF classes are not thread safe so sharing single context among all requests in your web application is going to hell. Context and its internals are not stateless so simply sharing them is very bad idea.

EF Distinct (IEqualityComparer) Error

Good Morning!
Given:
public class FooClass
{
public void FooMethod()
{
using (var myEntity = new MyEntity)
{
var result = myEntity.MyDomainEntity.Where(myDomainEntity => myDomainEntity.MySpecialID > default(int)).Distinct(new FooComparer);
}
}
}
public class FooComparer : IEqualityComparer<MyEntity.MyDomainEntity>
{
public bool Equals(MyEntity.MyDomainEntity x, MyEntity.MyDomainEntity y)
{
return x.MySpecialID == y.MySpecialID;
}
public int GetHashCode(MyEntity.MyDomainEntity obj)
{
return obj.MySpecialID.GetHashCode();
}
}
This will compile, but on runtime I will get an Linq to Entity could not translate Comparer-Exception.
Any suggestions?
If you're providing your own comparisons, you'll need to execute the Distinct call in .NET code. To make sure that happens, use AsEnumerable to turn IQueryable<T> into IEnumerable<T>:
var result = myEntity.MyDomainEntity
.Where(myDomainEntity => myDomainEntity.MySpecialID > default(int))
.AsEnumerable()
.Distinct(new FooComparer());
Of course at that point you'll be pulling more data across from the database. An alternative is to group the data instead:
var result = from entity in myEntity.MyDomainEntity
where entity.MySpecialID > 0
group entity by entity.MySpecialID into groups
select groups.FirstOrDefault();
That will get you the first entity encountered with each ID (assuming my query-fu isn't failing me). That's basically what Distinct does anyway, but it's all at the database.
(Note to future readers: calling First() makes more sense than FirstOrDefault(), but apparently that doesn't work.)

Categories