My interface is returning a IQueryable. The model TemplatesAgent with a template and IEnumerable<Agent> object. In my DataService I am collecting all of the agents in the ListOfAgent. I am then selecting the agent that are within the templates using the AgentVersionKey. This is the error I am getting is it related to the IQueryable type?
ExceptionMessage": "Explicit construction of entity type 'OrderTemplateTool.Data.Agent' in query is not allowed.",
Interface
IQueryable<TemplatesAgent> GetTemplateAgentNameDiseaseName(string agent, string disease);
DataService
public IQueryable<TemplatesAgent> GetTemplateAgentNameDiseaseName(string agent, string disease)
{
//Common
var ListOfAgent = (from a in UnitOfWork.GetRepository<Agent>().Get(a => !a.IsDeleted && a.IsCurrentVersion)
select new Agent
{
VersionKey = a.VersionKey,
Name = a.Name,
RxNormId = a.RxNormId,
BrandNames = a.BrandNames
});
var TemplatesAgent = (from t in UnitOfWork.GetRepository<Template>().Get()
join r in UnitOfWork.GetRepository<Regimen>().Get() on t.Id equals r.TemplateId
join rp in UnitOfWork.GetRepository<RegimenPart>().Get() on r.Id equals rp.RegimenId
join re in UnitOfWork.GetRepository<RegimenEntry>().Get() on rp.Id equals re.RegimenPartId
where t.IsCurrentVersion
&& t.Status == 7
select new TemplatesAgent
{
Template = t,
Agent = ListOfAgent.Where(x => x.VersionKey == re.AgentVersionKey).ToList()
});
Model
public class TemplatesAgent
{
public Template Template { get; set; }
public IEnumerable<Agent> Agent { get; set; }
}
Controller
[HttpGet]
public IHttpActionResult TemplatesList(string key, string disease = null, string agent = null)
{
var result = TemplatesDataService.GetTemplateAgentNameDiseaseName(agent, disease)
.Where(
t =>
t.Template.IsCurrentVersion && t.Template.Status == (short)TemplateMode.Published)
.OrderBy(t => t.Template.TemplateIdMain)
.ThenBy(t => t.Template.TemplateIdNumeric)
.ThenBy(t => t.Template.TemplateIdAlt)
.ToList()
.Select(t => new
{
TemplateId = t.Template.TemplateId,
RegimenTitle = t.Template.Title,
CourseTitle = t.Template.GroupTitle,
GuidelineTitle = t.Template.GuideLineTitle,
DiseaseId = t.Template.ExternalDiseaseId,
DiseaseName = t.Template.DiseaseName
Agent = t.Agent(a => new
{
VersionKey = a.VersionKey,
Name = a.Name,
BrandNames = a.BrandNames,
RxNormId = a.RxNormId
}).ToList(),
})
.Distinct().ToList();
return Json(result);
}
It is telling you that you can't make a new Agent inside the query. Try this.
var agentRepo = UnitOfWork.GetRepository<Agent>().Get();
var ListOfAgent = (from a in agentRepo
where !a.IsDeleted && a.IsCurrentVersion
select a);
var TemplatesAgent = (from t in UnitOfWork.GetRepository<Template>().Get()
join r in UnitOfWork.GetRepository<Regimen>().Get() on t.Id equals r.TemplateId
join rp in UnitOfWork.GetRepository<RegimenPart>().Get() on r.Id equals rp.RegimenId
join re in UnitOfWork.GetRepository<RegimenEntry>().Get() on rp.Id equals re.RegimenPartId
where t.IsCurrentVersion
&& t.Status == 7
select new TemplatesAgent
{
Template = t,
Agent = ListOfAgent.Where(x => x.VersionKey == re.AgentVersionKey).ToList()
});
Controller
[HttpGet]
public IHttpActionResult TemplatesList(string key, string disease = null, string agent = null)
{
var result = TemplatesDataService.GetTemplateAgentNameDiseaseName(agent, disease)
.Where(
t =>
t.Template.IsCurrentVersion && t.Template.Status == (short)TemplateMode.Published)
.OrderBy(t => t.Template.TemplateIdMain)
.ThenBy(t => t.Template.TemplateIdNumeric)
.ThenBy(t => t.Template.TemplateIdAlt)
.Distinct().ToList();
return Json(result);
}
Related
I've got a Linq query with 5 joins/tables, with predefined conditions.
Because I need the query multiple times I've created a function which returns the default LINQ query as an IQueryable.
public static IQueryable<MroomLinqModel> GetDefaultQuery(CustomerContext CustomerCtx)
{
var Mrooms = (from mr in CustomerCtx.Mrooms
join m in CustomerCtx.Moves on mr.MoveId equals m.MoveId
join mg in CustomerCtx.mgroup on m.MgroupId equals mg.MgroupId
join s in CustomerCtx.Status on m.StatusId equals s.StatusId
join rt in CustomerCtx.Roomtypes on mr.RoomtypeId equals rt.Key
join g in CustomerCtx.Guests on m.Mgroup.GuestId equals g.GuestId
where
Math.Abs(mg.Status) != (int)IResStatus.InComplete &&
s.Visible
select new MroomLinqModel
{
OpenDepositPayments = mg.DepositPayments.Any(dp => !dp.Paid),
RoomHidden = (mr.RoomId == null ? true : mr.Room.Hidden),
StatusVisible = s.Visible,
MroomId = mr.MroomId,
MoveId = m.MoveId,
MgroupId = mg.MgroupId,
StatusId = s.StatusId,
StatusFlags = s.Flags,
BackgroundColor = s.Background_Argb,
TextColor = s.Foreground_Argb,
PersonCount = m.Movegroups.Sum(m => m.PersonCount),
MoveCount = mg.Moves.Count(),
RoomId = mr.RoomId,
PMSMroomId = mr.PMS_Id,
PMSMoveId = m.PMS_Id,
PMSMgroupId = mg.MgroupId_Casablanca,
From = mr.From,
Until = mr.Until,
EditableState = m.EditableState,
MroomStatus = mr.Status,
RoomtypeUsage = mr.Roomtype.Usage,
BookingReference = mg.ReferenceNumber,
Guest = g
});
return Mrooms;
}
Now I would like to add some conditions afterwards like:
Query = GetDefaultQuery.Where(q => !q.RoomHidden && q.From <= dtLoadEnd && dtLoadStart <= q.Until);
Query = Query.Where(q => q.RoomtypeUsage == RoomtypeUsageType.Roomplan);
This works fine but takes a lot more time to execute as if I add all conditions directly to the first LINQ query.
How do I form the query to access the original tables and generate a fast query?
Since all your condition match the table where you are joining the other tables you can add the conditions before your multi join, I got 2 suggestions for you, either create another method that filters your conditions predefined or add to your method optional filters like so :
public static IQueryable<MroomLinqModel> GetDefaultQuery(CustomerContext CustomerCtx, bool? roomHidden, DateTime? dtLoadEnd
/* you can add more parameters but for demonstrations purposes i'm only describing this 2*/)
{
var query = CustomerCtx.Mrooms;
if(roomHidden.HasValue)
{
query = query.Where( q=>q.From == roomHidden.Value)
}
if(dtLoadEnd .HasValue)
{
query = query.Where( q=>q.RoomHidden <= dtLoadEnd.Value)
}
// you can add more conditions
var Mrooms = (from query
join m in CustomerCtx.Moves on mr.MoveId equals m.MoveId
join mg in CustomerCtx.mgroup on m.MgroupId equals mg.MgroupId
join s in CustomerCtx.Status on m.StatusId equals s.StatusId
join rt in CustomerCtx.Roomtypes on mr.RoomtypeId equals rt.Key
join g in CustomerCtx.Guests on m.Mgroup.GuestId equals g.GuestId
where
Math.Abs(mg.Status) != (int)IResStatus.InComplete &&
s.Visible
select new MroomLinqModel
{
OpenDepositPayments = mg.DepositPayments.Any(dp => !dp.Paid),
RoomHidden = (mr.RoomId == null ? true : mr.Room.Hidden),
StatusVisible = s.Visible,
MroomId = mr.MroomId,
MoveId = m.MoveId,
MgroupId = mg.MgroupId,
StatusId = s.StatusId,
StatusFlags = s.Flags,
BackgroundColor = s.Background_Argb,
TextColor = s.Foreground_Argb,
PersonCount = m.Movegroups.Sum(m => m.PersonCount),
MoveCount = mg.Moves.Count(),
RoomId = mr.RoomId,
PMSMroomId = mr.PMS_Id,
PMSMoveId = m.PMS_Id,
PMSMgroupId = mg.MgroupId_Casablanca,
From = mr.From,
Until = mr.Until,
EditableState = m.EditableState,
MroomStatus = mr.Status,
RoomtypeUsage = mr.Roomtype.Usage,
BookingReference = mg.ReferenceNumber,
Guest = g
});
return Mrooms;
}
expecting that CustomerCtx.Mrooms is a DbSet<Mroom> and that Mroom looks like :
public class Mroom {
public int MroomId {get; set;}
[ForeignKey("Move")]
public int MoveId {get; set;} //FK
public virtual Move Move {get; set;} //Navigation property
//configuration may be needed cf annotation
[ForeignKey("Status")]
public int StatusId {get; set;}
public virtual Status Status {get; set;}
//... Mgroup, Guest, ...
}
If it is not the case I suggest you yo refactor your code to use navigation properties.
Then you may use PredicateBuilder of linqkit as follow:
public static IQueryable<MroomLinqModel> GetDefaultQuery(CustomerContext CustomerCtx, Expression<Function<Mroom, bool>> q)
{
Expression<Function<Mroom, bool>> w = PredicateBuilder.New<Mroom>
(s => Math.Abs(s.Mgroup.Status) != (int)IResStatus.InComplete &&
s.Visible);
w = w.And(q);
return
CustomerCtx.Mrooms.
Where(w.Expand()).
Select( x => new MroomLinqModel
{
OpenDepositPayments = x.Mgroup.DepositPayments.Any(dp => !dp.Paid),
RoomHidden = (x.RoomId == null ? true : x.Room.Hidden),
StatusVisible = x.Status.Visible,
MroomId = x.MroomId,
MoveId = x.MoveId,
MgroupId = x.MgroupId,
StatusId = x.Status.StatusId,
StatusFlags = x.Status.Flags,
BackgroundColor = x.Status.Background_Argb,
TextColor = x.Status.Foreground_Argb,
PersonCount = x.Move.Movegroups.Sum(m => m.PersonCount),
MoveCount = x.Mgroup.Moves.Count(),
RoomId = x.RoomId,
PMSMroomId = x.PMS_Id,
PMSMoveId = x.Move.PMS_Id,
PMSMgroupId = x.Mgroup.MgroupId_Casablanca,
From = x.From,
Until = x.Until,
EditableState = x.Move.EditableState,
MroomStatus = x.Move.Status,
RoomtypeUsage = mr.Roomtype.Usage,
BookingReference = x.Mgroup.ReferenceNumber,
Guest = x.Guest
}
);
}
and use it as:
GetDefaultQuery(ctx, q => !q.RoomHidden && q.From <= dtLoadEnd && dtLoadStart <= q.Until);
and or
Expression<Function<Mroom, bool>> w = PredicateBuilder.New<Mroom>(q =>
!q.RoomHidden && q.From <= dtLoadEnd && dtLoadStart <= q.Until);
//some logic
w = w.And(q => q.RoomtypeUsage == RoomtypeUsageType.Roomplan);
GetDefaultQuery(ctx, w);
This query does work, but I am trying to combine the two steps into one query.
var query1 = from b in db.GetTable<Boats>()
from o in db.GetTable<Offices>()
from u in db.GetTable<Users>()
.Where
(u =>
u.UserId == b.Handling_broker &&
o.Office == b.Handling_office &&
b.Status == 2 &&
officesToInclude.Contains(b.Handling_office)
)
select new
{
hOffice = o.Name,
bName = u.Name
};
var query2 = query1.GroupBy(t => new { office = t.hOffice, name = t.bName })
.Select(g => new { Office = g.Key.office, Name = g.Key.name, Count = g.Count() });
If I try to combine the two queries using the following query it gives me the “A query body must end with a select clause or a group clause” error.
var query1 = from b in db.GetTable<Boats>()
from o in db.GetTable<Offices>()
from u in db.GetTable<Users>()
.Where
(u =>
u.UserId == b.Handling_broker &&
o.Office == b.Handling_office &&
b.Status == 2 &&
officesToInclude.Contains(b.Handling_office)
)
.GroupBy(t => new { office = t.Office, name = t.Name })
.Select(g => new { Office = g.Key.office, Name = g.Key.name, Count = g.Count() });
I think I have to add a select something, but I can't figure out what.
Can anyone please help?
Your query must contain a select clause. The .Where(...).GroupBy(...).Select(...) are only on the db.GetTable<Users>(). Something like:
var query1 = from b in db.GetTable<Boats>()
from o in db.GetTable<Offices>()
from u in db.GetTable<Users>().Where(u => u.UserId == b.Handling_broker &&
o.Office == b.Handling_office &&
b.Status == 2 &&
officesToInclude.Contains(b.Handling_office))
.GroupBy(t => new { office = t.Office, name = t.Name })
.Select(g => new { Office = g.Key.office, Name = g.Key.name, Count = g.Count() })
select new { /* Desired properties */};
But I think you are looking for something like:
var result = from b in db.GetTable<Boats>()
from o in db.GetTable<Offices>()
from u in db.GetTable<Users>()
where u.UserId == b.Handling_broker &&
o.Office == b.Handling_office &&
b.Status == 2 &&
officesToInclude.Contains(b.Handling_office))
group 1 by new { t.Office, t.Name } into g
select new { Office = g.Key.Office, Name = g.Key.Name, Count = g.Count() };
I have 2 tables, one is Orders, that holds the address/list of products, and a returnDetails table. This is used when a user wants to return an Order. The returnDetails has the OrderId that is being returned.
How do I display a message only on the orders that have a return with the same OrderID? Currently only "processing" is displayed.
I used a view model to display the Orders with products.
Here is what I tried but I haven't got it working yet:
[Authorize]
public ActionResult Index(string date)
{
string currentUser = this.User.Identity.GetUserName();
List<T_shirt_Company_v3.ViewModels.MyOrdersViewModel> list = (from o in new TshirtStoreDB().Orders
.Where(o => o.Username == currentUser)
.OrderByDescending(o => o.OrderDate)
.Select(o => new MyOrdersViewModel()
{
OrderId = o.OrderId,
Address = o.Address,
FirstName = o.FirstName,
LastName = o.LastName,
City = o.City,
OrderDate = o.OrderDate,
PostalCode = o.PostalCode,
Total = o.Total,
HasBeenShipped = o.HasBeenShipped,
PostageList = o.PostageList,
Details = (from d in o.OrderDetails
select new MyOrderDetails
{
Colour = d.Product.Colour,
Quantity = d.Quantity,
Title = d.Product.Title,
UnitPrice = d.UnitPrice
}).ToList()
}).ToList() select o).ToList();
if (date != null)
{
DateTime today = DateTime.Now.AddDays(Convert.ToInt32(date) * -1);
return View(list.Where(x => x.OrderDate >= today).ToList());
}
//WORKING ON
var returnstats = db.Orders.Where(x => x.OrderId == x.returnDetails.OrderId).ToList();
if (returnstats != null)
{
ViewBag.returnstats = "Returning Item";
}
else
{
ViewBag.returnstats = "processing";
}
return View(list);
}
I think the problem is that you are not clear about what is the business logic for 'returnstats'. From the values of this variable you provide, it looks like it's for a SINGLE order instead of an order list. Here is a modified Index method for your reference:
[Authorize]
public ActionResult Index(Int32? days)
{
string currentUser = this.User.Identity.GetUserName();
var orders = db.Orders //assume db is something inherited from DbContext
.Where(o => o.UserName == currentUser)
.OrderByDescending(o => o.OrderDate);
if (days.HasValue)
{
var startingDate = DateTime.Now.AddDays((-1) * days.Value);
orders = orders.Where(o => o.OrderDate >= startingDate);
}
var orderList = orders.ToList();
var returnOrderIds = db.ReturnDetails.Select(detail => detail.OrderId).ToList();
//here you will need to check with business analyst staff what is the rule for 'returnstats'.
//The business logic here is that if there is at least one order whose OrderId is in the ReturnDetails
//the 'returnstats' is 'Returning Item' otherwise it's 'Processing'.
if (orderList.Any(o => returnOrderIds.Contains(o.OrderId))
{
ViewBag.returnstats = "Returning Item";
} else
{
ViewBag.returnstats = "processing";
}
var viewModels = ...//the source code to create Order ViewModel with variable orderList
return View(viewModels);
}
I'm returning anonymouse type from my webapi controller, one of the values I need to be computed by using function. When I'm trying to do this way getting error say "Several actions were found that match request".
Here is how I call GET:
// GET api/Grafik/5
public IHttpActionResult GetGrafik(int id)
{
xTourist t = db.xTourist.Find(id);
var beach = db.xAdres.Find(t.Hotel).Kod;
var result = from a in db.Grafik
join b in db.Excursions on a.Excursion equals b.Kod
join c in db.Dates on a.KodD equals c.KodD
join d in db.Staff on a.Guide equals d.Kod
where c.Date > t.ArrDate && c.Дата < t.DepDate
let pu = from x in db.xPickUp where x.KodP == beach && x.Excursion == b.Kod select x.PickUpTime
orderby c.Date
select new { kodg = a.Kodg, excursion = b.Name, guide = d.GuideName, data = c.Date, pricead = b.Price,
pricech = b.PriceChd, pax = t.Pax, child = t.Ch, paxleft = GetPax(a.Kodg), pickup = pu.FirstOrDefault()};
return Ok(result);
}
And here is the function returning needed value:
public int GetPax(int id)
{
//get pax quota
var pre = db.Grafik.Where(k => k.Kodg == id).Select(p => p.Quota).SingleOrDefault();
if (pre.HasValue && pre.Value > 0)
{
//Get taken pax
var p = (from a in db.Orders where a.Kodg == id & !(a.Cansel == true) select a.Child).Sum();
var c = (from a in db.Orders where a.Kodg == id & !(a.Cansel == true) select a.Pax).Sum();
if (p.HasValue & c.HasValue)
{
return pre.Value - (p.Value + c.Value);
}
else
{
return pre.Value;
}
}
else
{
return 0;
}
}
Web API is seeing two public methods with id as a parameter and it can't figure out which one to execute when you send your request. Looking at your code, there's no need for the helper method GetPax() to be public. Try changing it to private.
private int GetPax(int id) // ...
I found solution. Ok, this could be a bit strange way, but it's working.
public IHttpActionResult GetГрафик(int id)
{
xTourist t = db.xTourist.Find(id);
var beach = db.xAdres.Find(t.Hotel).Kod;
var result = from a in db.Grafik
join b in db.Excursions on a.Excursion equals b.Kod
join c in db.Dates on a.Kodd equals c.Kodd
join d in db.Staff on a.Guidename equals d.Kod
join e in db.Заказы on a.КодГ equals e.КодГ
where c.Дата > t.Датапр && c.Дата < t.Датаотл
let pu = from x in db.xPickUp where x.КодП == beach && x.Excursion == b.Kod select x.PickUpTime
orderby c.Дата
let pl = a.Пребукинг - (e.Child + e.Pax)
select new { kodg = a.КодГ, excursion = b.Название, guide = d.Name, data = c.Дата, pricead = b.Price,
pricech = b.PriceChd, pax = t.Колчел, child = t.Дети, paxleft = pl, pickup = pu.FirstOrDefault()};
return Ok(result);
}
I'm using VS2010 Entity Framework to store a value in a session. I the use syntax below:
private IEnumerable _TransactionItem2
{
get
{
var msg = HttpContext.Current.Session["SESSION_MESSAGES_NAME"] as IEnumerable;
if (msg == null)
{
msg = new BOMDetailController().GetSearchData(0, 0);
HttpContext.Current.Session["SESSION_MESSAGES_NAME"] = msg;
}
return msg;
}
set
{
Session[_MenuName + "TransactionItem"] = value;
}
}
Session initialization method below:
public IEnumerable GetSearchData(int companyID = 0, long bOMID = 0)
{
var itemBrand = (from p in this.controllerCMN.Context.CmnItemBrands where p.IsDeleted == false select p).AsEnumerable();
var itemColor = (from p in this.controllerCMN.Context.CmnItemColors where p.IsDeleted == false select p).AsEnumerable();
var itemMaster = (from p in this.controllerCMN.Context.CmnItemMasters where p.IsDeleted == false select p).AsEnumerable();
var itemSpecificationMaster = (from p in this.controllerCMN.Context.CmnItemSpecificationMasters where p.IsDeleted == false select p).AsEnumerable();
var itemStyleMaster = (from p in this.controllerCMN.Context.CmnItemStyleMasters where p.IsDeleted == false select p).AsEnumerable();
var uOM = (from p in this.controllerCMN.Context.CmnUOMs where p.IsDeleted == false select p).AsEnumerable();
var bnOMMaster = (from p in this.Context.PlnBOMMasters where p.IsDeleted == false && p.CompanyID == companyID select p).AsEnumerable();
var prdPhase = (from p in this.Context.PlnPrdPhases where p.IsDeleted == false && p.ComapnyID == companyID select p).AsEnumerable();
var prdTask = (from p in this.Context.PlnPrdTasks where p.IsDeleted == false && p.ComapnyID == companyID select p).AsEnumerable();
var bOMDetail = (from p in this.Context.PlnBOMDetails where p.IsDeleted == false && p.CompanyID == companyID select p).AsEnumerable();
var query = from p in bOMDetail
select new
{
BOMDetailRecordID = p.BOMDetailRecordID,
CustomCode = p.CustomCode,
BOMID = p.BOMID,
BOMName = (from q in bnOMMaster where q.BOMID == p.BOMID select q.Description).FirstOrDefault(),
PhaseID = p.PhaseID,
PhaseName = (from q in prdPhase where q.PhaseID == p.PhaseID select q.PhaseName).FirstOrDefault(),
ItemID = p.ItemID,
ItemName = (from q in itemMaster where q.ItemID == p.ItemID select q.ItemName).FirstOrDefault(),
ColorID = p.ColorID,
ColorName = (from q in itemColor where q.ColorID == p.ColorID select q.ColorName).FirstOrDefault(),
StyleID = p.StyleID,
StyleName = (from q in itemStyleMaster where q.StyleID == p.StyleID select q.StyleName).FirstOrDefault(),
ItemSpecificationID = p.ItemSpecificationID,
ItemSpecificationName = (from q in itemSpecificationMaster where q.ItemSpecificationID == p.ItemSpecificationID select q.Description).FirstOrDefault(),
ItemBrandID = p.ItemBrandID,
BrandName = (from q in itemBrand where q.ItemBrandID == p.ItemBrandID select q.ItemBrandName).FirstOrDefault(),
UOMID = p.UOMID,
UOMName = (from q in uOM where q.UOMID == p.UOMID select q.UOMName).FirstOrDefault(),
ItemQty = p.ItemQty,
UnitPrice = p.UnitPrice,
StatusID = p.StatusID,
};
return query.WhereIf(bOMID != 0, p => p.BOMID == bOMID).OrderByDescending(w => w.BOMDetailRecordID);
}
I want to query on the above property TransactionItem2.
1) I want to count how many items on the property TransactionItem2
`TransactionItem2.AsQueryable().Count()`
2) I want to query on this like:
var entity = _ TransactionItem2.SingleOrDefault(item => item.BOMDetailRecordID == childRecordID);
3) I want to use a query
var entity = _ TransactionItem2.Where(item => item.BOMDetailRecordID == childRecordID);
My Extension method is
public static TSource Single<TSource>(this IEnumerable source)
{
return source.Cast<TSource>().Single();
}
public static TSource Single<TSource>(this IEnumerable source, Func<TSource, bool> predicate)
{
return source.Cast<TSource>().Single(predicate);
}
public static TSource SingleOrDefault<TSource>(this IEnumerable source)
{
return source.Cast<TSource>().SingleOrDefault();
}
public static TSource SingleOrDefault<TSource>(this IEnumerable source, Func<TSource, bool> predicate)
{
return source.Cast<TSource>().SingleOrDefault(predicate);
}
Working syntax:
var entity = _TransactionItem2.SingleOrDefault(item => item.BOMDetailRecordID == childRecordID);
The above syntax shows an error message:
“cannot be inferred from the usage. Try specifying the type arguments
explicitly”
The above syntax is not working for the property TransactionItem2. Why is 1,2,3 not working?
You have to specify TSource explicitly when calling your methods:
var entity = _TransactionItem2.SingleOrDefault<EntityClass>(item => item.BOMDetailRecordID == childRecordID);