Better way to fecth data for EF - entity-framework

We have DB on which CDC is enabled. We had to find the data on basis of date supplied. So we had implemented the data fetch through db functions.
The code block is as follows:
private IQueryable<Letter> GetLetterQuery(DateTime? date = null)
{
IQueryable<Letter> dataSource = null;
dataSource = DBContextHelper.Context.fnGetLetters(date);
return dataSource;
}
public List<Letter> GetLetters(int attemptID, int cycle)
{
var dataSource = GetLetterQuery(DBContextHelper.CurrentDataVersion).Where(u => u.AttemptID == attemptID && u.Cycle == cycle).ToList();
populateLettersChildEntities(dataSource, DBContextHelper.CurrentDataVersion);
return dataSource;
}
private void populateLettersChildEntities(List<Letter> letters, DateTime? date = null)
{
letters.ForEach(u =>
{
u.Documents = DBContextHelper.Context.fnGetDocuments(date).Where(d => d.LetterID == u.ID).ToList();
u.LetterDoctors = DBContextHelper.Context.fnGetLetterDoctor(date).Where(d => d.LetterID == u.ID).ToList();
u.LetterFields = DBContextHelper.Context.fnGetLetterFields(date).Where(d => d.LetterID == u.ID).ToList();
u.LetterDoctors.ForEach(d =>
{
d.Doctor = DBContextHelper.Context.fnGetDoctors(date).FirstOrDefault(q => q.IDdoctor == d.DoctorID);
d.Letter = u;
});
});
}
We had to fill the associated fields. Our problem is that it results in many db calls definitely. Is there any way to reduce the calls? AFAIK we are not able to use the include with such db calls.

Related

Getting WorkbookPart from row

I am writing and extension for OpenXML like shown in the sample. I would like to avoid having to pass the WorkbookPart as parameter. Is there any way to get the WorkbookPart directly from the row?
public static string GetCellTextValue(this Row row, WorkbookPart workbookPart, string column)
{
var cells = row.Elements<Cell>();
var cell = cells.Where(p => p.CellReference == column + row.RowIndex.ToString()).FirstOrDefault();
if (cell.DataType != null)
{
if (cell.DataType == CellValues.SharedString)
{
int id = -1;
if (Int32.TryParse(cell.InnerText, out id))
{
SharedStringItem item = workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(id);
if (item.Text != null)
{
return item.Text.Text;
}
else if (item.InnerText != null)
{
return item.InnerText;
}
else if (item.InnerXml != null)
{
return item.InnerXml;
}
}
}
}
return string.Empty;
}
Unfortunately, none of the strongly-typed classes of the Open XML SDK (e.g., Workbook, Worksheet, Row) have properties pointing back to the OpenXmlPart (e.g., WorkbookPart, WorksheetPart) in which they are contained or any other part related to their immediate container. Unless you amend your API in other ways, you will have to pass that WorkbookPart.

how can I write generic queries in entity framework?

I have 3 methods these are same methods only some parameters will be change I want to write one method how can i write
public string method1(int id)
{
var getAllStudents = rep.Students.Where(e => e.StudentId == id).ToList();
foreach (var item in getAllStudents)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
public string method2(int id)
{
var getAllTeachers = rep.Teachers.Where(e => e.TeacherId == id).ToList();
foreach (var item in getAllTeachers)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
public string method3(int id)
{
var getAllClasses = rep.Classes.Where(e => e.ClassId == id).ToList();
foreach (var item in getAllClasses)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
I think there is very easy way to write 1 method. the think is where parameter has different id..
Thanks.
Avoid conditional logic based on arguments. This leads to fragile code because every parameter combination has to be tested to be considered reliable. This leads to complex code that is easily prone to bugs. Having simpler single-purpose methods are typically much more reliable and easier to understand and maintain.
For instance given your example and assuming that "rep" was your instance's DbContext...
public bool IsActiveStudent(int id)
{
bool result = rep.Students.Any(x => x.StudentId == id && x.IsActive);
return result;
}
public bool IsActiveTeacher(int id)
{
bool result = rep.Teachers.Any(x => x.TeacherId == id && x.IsActive);
return result;
}
public bool IsActiveClass(int id)
{
bool result = rep.Classes.Any(x => x.ClassId == id && x.IsActive);
return result;
}
These can be essentially one-liners by simply returning the .Any() result. I tend to favour selecting the result into a variable first and returning it on a separate line since it makes it easier to breakpoint and inspect.
If you need to return a string for "Ok" vs. "Error" then:
return result ? "OK" : "Error";
Methods should strive to do one thing, and do it well. Easy to understand and troubleshoot if need be. Adding parameters and conditional code inside the method merely makes the code more volatile and leaves openings for bugs. In the end it doesn't make the code much shorter when the initial method could be simplified.
You can not overload methods if they signatures are the same.
You have two methods with the same signature:
public string checkexist(int id)
What you can do is to rename your methods, like this:
public interface WriteSomethingHere {
public boolean isStudentExist(int id);
public boolean isTeacherExist(int id);
public boolean isClassExist(int id);
}
I just found answer using generic repo
public T GetEntity<T>(int Id)
where T : class
{
using (MyEntities rpContext = new MyEntities())
{
return rpContext.Set<T>().Find(e => e.Id == Id);
}
}
after calling
var entityStudent = GetEntity<Student>(1);
var entityTeacher = GetEntity<Teacher>(1);
var entityClasses = GetEntity<Classes>(1);
You have Create Enumeration
Public Enum ParameterStaus:short
{
Student=1,
Teacher=2,
Classess=3
}
public string method2(int id.ParameterStatus status)
{
if(status==ParameterStatus.Teacher)
{
var getAllTeachers = rep.Teachers.Where(e => e.TeacherId == id).ToList();
foreach (var item in getAllTeachers )
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
}
Else if(status==ParameterStatus.Student)
{
var getAllStudents = rep.Students.Where(e => e.StudentId == id).ToList();
foreach (var item in getAllStudents)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
Else
{
var getAllClasses = rep.Classes.Where(e => e.ClassId == id).ToList();
foreach (var item in getAllClasses)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
}

Entity Framework - LINQ - Use Expressions in Select

I am using within my code some EF LINQ expressions to keep complex queries over my model in one place:
public static IQueryable<User> ToCheck(this IQueryable<User> queryable, int age, bool valueToCheck = true)
{
return queryable.Where(ToBeReviewed(age, valueToCheck));
}
public static Expression<Func<User, bool>> ToCheck(int age, bool valueToCheck = true)
{
return au => au.Status == UserStatus.Inactive
|| au.Status == UserStatus.Active &&
au.Age.HasValue && au.Age.Value > age;
}
I am then able to use them in queries:
var globalQuery = db.Users.ToCheck(value);
And also in selects:
var func = EntityExtensions.ToCheck(value);
var q = db.Department.Select(d => new
{
OrdersTotal = d.Orders.Sum(o => o.Price),
ToCheck = d.Users.AsQueryable().Count(func),
})
What I am trying to achieve is to actually use the same expression/function within a select, to evaluate it for each row.
var usersQuery = query.Select(au => new {
Id = au.Id,
Email = au.Email,
Status = au.Status.ToString(),
ToBeChecked = ???, // USE FUNCTION HERE
CreationTime = au.CreationTime,
LastLoginTime = au.LastLoginTime,
});
I am pretty that threre would be a way using plain EF capabilities or LINQKit, but can't find it.
Answering my own question :)
As pointed by #ivan-stoev, the use of Linqkit was the solution:
var globalQueryfilter = db.Users.AsExpandable.Where(au => au.Department == "hq");
var func = EntityExtensions.ToCheck(value);
var usersQuery = globalQueryfilter.Select(au => new
{
Id = au.Id,
Email = au.Email,
Status = au.Status.ToString(),
ToBeChecked = func.Invoke(au),
CreationTime = au.CreationTime,
LastLoginTime = au.LastLoginTime,
});
return appUsersQuery;
It's required to use the AsExpandable extension method from Linqkit along with Invoke with the function in the select method.
I want to add one more example:
Expression<Func<AddressObject, string, string>> selectExpr = (n, a) => n == null ? "[no address]" : n.OFFNAME + a;
var result = context.AddressObjects.AsExpandable().Select(addressObject => selectExpr.Invoke(addressObject, "1"));
Also, expression can be static in a helper.
p.s. please not forget to add "using LinqKit;" and use "AsExpandable".

Can I convert this extension method to use IDbSet<> instead of DbContext?

Currently I use the below method like this: db.GetProjectsAllowed(profileId, profOrgList, projectList). I would like to convert this to use IDbSet<Project>, but I'm not sure how to get the second LINQ query.
public static IQueryable<Project> GetProjectsAllowed
(
this IMkpContext db,
Guid profileId,
List<Guid> profOrgIds = null,
List<Guid> projectIds = null
)
{
var projects =
(
from p in db.Project
.Include(p => p.Proposals)
.Include(p => p.RoleAssignments)
.Include("RoleAssignments.AssigneeSnapshot")
where p.IsActive
select p);
if (profOrgIds != null && profOrgIds.Any())
{
var profileIds = db.ProfileOrganization
.Where(po => po.IsActive && profOrgIds.Contains(po.OrganizationId))
.Select(po => po.ProfileId);
projects = projects.Where(p => profileIds.Contains(p.CreatedById));
}
if (projectIds != null && projectIds.Any())
projects = projects.Where(proj => projectIds.Contains(proj.ProjectId));
return projects;//.ToList();
}
Can I convert this to use IDbSet<Project> or not?
Here, why not split this into two extension methods? This makes your GetProjectsAllowed extension method more cohesive and single responsible.
First:
public static IEnumerable<Guid> GetProfileIds(
this IDbSet<ProfileOrganization> profileOrganizations,
IEnumerable<Guid> profOrgIds = null)
{
return profOrgIds == null ? null :
from po in profileOrganizations
where po.IsActive
where profOrgIds.Contains(po.OrganizationId)
select po.OrganizationId;
}
And second:
public static IQueryable<Project> GetProjectsAllowed(
this IDbSet<Project> projects,
IEnumerable<Guid> profileIds,
IEnumerable<Guid> projectIds = null)
{
var activeProjects =
from project in projects
//.Include(..
where project.IsActive
select project;
if (profileIds != null && profileIds.Any())
{
activeProjects = activeProjects.Where(p => profileIds.Contains(p.CreatedById));
}
if (projectIds != null && projectIds.Any())
{
activeProjects = activeProjects.Where(proj => projectIds.Contains(proj.ProjectId));
}
return activeProjects;//.ToList();
}
And then the consumer can call it like this:
var profileIds = db.ProfileOrganization.GetProfileIds(profOrgIds);
var projectsAllowed = db.Projects.GetProjectsAllowed(profileIds, projectIds);

Entity Framework, building query based on criteria

I was wondering if anyone had a better idea how to do this. atm returning IQueryable<Member> as ObjectQuery<Member> seems dirty to me.
namespace Falcon.Business.Repositories
{
using System;
using System.Data.Objects;
using System.Linq;
using Falcon.Business.Criteria;
using Falcon.Business.Entities;
using Falcon.Business.Enums;
using Falcon.Business.Extensions;
using Falcon.Business.Repositories.Interfaces;
using Falcon.Business.Services;
using Falcon.Business.Services.Interfaces;
using Falcon.Core.Extensions;
public class MemberRepository : LinqRepository<Member>, IMemberRepository
{
public Member Fetch(MemberCriteria criteria)
{
ObjectQuery<Member> query = base.CreateQuery();
query = this.AddRelations(query);
query = this.AddCriteria(query, criteria);
query = this.AddCriteriaOrder(query, criteria);
return query.FirstOrDefault();
}
public IPagerService<Member> FetchAll(MemberCriteria criteria)
{
int page = (criteria.Page.HasValue) ? criteria.Page.Value : 1;
int limit = criteria.Limit;
int start = (page * limit) - limit;
int total = this.Count(criteria);
ObjectQuery<Member> query = base.CreateQuery();
query = this.AddRelations(query);
query = this.AddCriteria(query, criteria);
query = this.AddCriteriaOrder(query, criteria);
return new PagerService<Member>(query.Skip(start).Take(limit).ToList(), page, limit, total);
}
public int Count(MemberCriteria criteria)
{
ObjectQuery<Member> query = base.CreateQuery();
query = this.AddCriteria(query, criteria);
return query.Count();
}
public ObjectQuery<Member> AddCriteria(IQueryable<Member> query, MemberCriteria criteria)
{
if (criteria.Title.HasValue())
{
query = query.Where(q => q.Title == criteria.Title);
}
if (criteria.TitleUrl.HasValue())
{
query = query.Where(q => q.TitleUrl == criteria.TitleUrl);
}
if (criteria.EmailAddress.HasValue())
{
query = query.Where(q => q.EmailAddress == criteria.EmailAddress);
}
if (criteria.HostAddress.HasValue())
{
query = query.Where(q => q.HostAddress == criteria.HostAddress);
}
query = query.Where(q => q.Status == criteria.Status);
return query as ObjectQuery<Member>;
}
public ObjectQuery<Member> AddCriteriaOrder(IQueryable<Member> query, MemberCriteria criteria)
{
if (criteria.Sort == SortMember.ID)
{
query = criteria.Order == SortOrder.Asc
? query.OrderBy(q => q.ID)
: query.OrderByDescending(q => q.ID);
}
else if (criteria.Sort == SortMember.Posts)
{
query = criteria.Order == SortOrder.Asc
? query.OrderBy(q => q.Posts)
: query.OrderByDescending(q => q.Posts);
}
else if (criteria.Sort == SortMember.Title)
{
query = criteria.Order == SortOrder.Asc
? query.OrderBy(q => q.Title)
: query.OrderByDescending(q => q.Title);
}
else if (criteria.Sort == SortMember.LastLogin)
{
query = criteria.Order == SortOrder.Asc
? query.OrderBy(q => q.LastLogin)
: query.OrderByDescending(q => q.LastLogin);
}
else if (criteria.Sort == SortMember.LastVisit)
{
query = criteria.Order == SortOrder.Asc
? query.OrderBy(q => q.LastVisit)
: query.OrderByDescending(q => q.LastVisit);
}
else
{
query = criteria.Order == SortOrder.Asc
? query.OrderBy(q => q.Created)
: query.OrderByDescending(q => q.Created);
}
return query as ObjectQuery<Member>;
}
private ObjectQuery<Member> AddRelations(ObjectQuery<Member> query)
{
query = query.Include(x => x.Country);
query = query.Include(x => x.TimeZone);
query = query.Include(x => x.Profile);
return query;
}
}
}
I also do not like returning an objectquery, because doing so will make you very dependent on Entity Framwork. Knowing Microsoft they propably make a lot of changes in version 2, so you do not want to do this.
NHibernate uses criteria, a bit like you suggested, but their implementation is a lot more generic. I like the more generic implementation more then you example because then you do not need to build criteria for every object. On the other hand, you implementation is typed, which is also very neat. If you want the best of both, a more generic implementation that is typed, you might want to take a look at the NHibernate implementation but instead of using strings, use lambda functions and .Net generics. I could post an example how to do this, but I'm currently not on my own machine.