Hello i'd like to create relation between EF Poco and DTO.
Here is my situation
I've got these 2 entities in my application
public partial class RFID_TAG
{
public int TAG_ID { get; set; }
public string RFID { get; set; }
public Nullable<int> EMPLOYEE_ID{ get; set; }
public virtual EMPLOYEE EMPLOYEE{ get; set; }
}
public partial class EMPLOYEE
{
public int EMPLOYEE_ID{ get; set; }
public string FIRST_NAME{ get; set; }
public string LAST_NAME{ get; set; }
//ETC...
}
I also have this DTO
public class EMPLOYEELookUpData
{
public int EMPLOYEE_ID{ get; set; }
public string FULL_NAME{ get; set; }
}
I'm using this DTO for specific selects where i only need EMPLOYEE's id and name, I've got CRUD view where user can add new tags it contains datagrid with that contains all tags and textbox thats bound to currently selected tags RFID and combobox which has SelectedItem bound to currently selected tags EMPLOYEE property. This is how i'm selecting data:
private async void GetData()
{
Data = await DbContext.RFID_TAG.Include(x => x.EMPLOYEE).ToListAsync();
EmployeesList = await DbContext.MPLOYEE.Where(x => x.ACTIVE == 1)
.Select(x => new EMPLOYEELookUpData{EMPLOYEE_ID = x.EMPLOYEE_ID, FULL_NAME= x.FIRST_NAME + " " + x.LAST_NAME})
.ToListAsync();
}
But i can't figure how to make relation between EMPLOYEE and EMPLOYEELookUpData so that EF knows how to convert EMPLOYEELookUpData to EMPLOYEE.
I believe you can use AutoMapper for this: https://www.nuget.org/packages/AutoMapper/. It can be installed using Nuget.
The code would look something like this:
using (MyEntities myEntities = new MyEntities())
{
List<EMPLOYEELookUpData> employeeLookupData;
try
{
employeeLookupData = myDB
.Employee
.Select(EMPLOYEELookUpData)
.Where(c => x => x.ACTIVE == 1)
.ToList();
}
catch (InvalidOperationException e)
{
//Write a log entry
}
I have not tested the code. You would have to create the mappings and create special mappings for : EMPLOYEELookUpData .FullName as it equals EMPLOYEE.FirstName + EMPLOYEE.Surname. You can find out how to do this by reading the documentation or posting another question on here.
Related
Multiple answers have led me to the following 2 solutions, but both of them do not seem to be working correctly.
What I have are 2 objects
public class DatabaseAssignment : AuditableEntity
{
public Guid Id { get; set; }
public string User_Id { get; set; }
public Guid Database_Id { get; set; }
}
public class Database : AuditableEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Server { get; set; }
public bool IsActive { get; set; }
public Guid DatabaseClientId { get; set; }
}
Now, the front-end will return all selected Database objects (as IEnumerable) for a given user. I am grabbing all current DatabaseAssignments from the database for the given user and comparing them to the databases by the Database.ID property. My goal is to find the DatabaseAssignments that I can remove from the database. However, my solutions keep returning all DatabaseAssignments to be removed.
if (databases != null)
{
var unitOfWork = new UnitOfWork(_context);
var userDatabaseAssignments = unitOfWork.DatabaseAssignments.GetAll().Where(d => d.User_Id == user.Id);
//var assignmentsToRemove = userDatabaseAssignments.Where(ud => databases.Any(d => d.Id != ud.Database_Id));
var assignmentsToRemove = userDatabaseAssignments.Select(ud => userDatabaseAssignments.FirstOrDefault()).Where(d1 => databases.All(d2 => d2.Id != d1.Database_Id));
var assignmentsToAdd = databases.Select(d => new DatabaseAssignment { User_Id = user.Id, Database_Id = d.Id }).Where(ar => assignmentsToRemove.All(a => a.Database_Id != ar.Database_Id));
if (assignmentsToRemove.Any())
{
unitOfWork.DatabaseAssignments.RemoveRange(assignmentsToRemove);
}
if (assignmentsToAdd.Any())
{
unitOfWork.DatabaseAssignments.AddRange(assignmentsToAdd);
}
unitOfWork.SaveChanges();
}
I think u are looking for an Except extension, have a look at this link
LINQ: Select where object does not contain items from list
Or other way is with contains see below Fiddler link :
https://dotnetfiddle.net/lKyI2F
Can someone suggest me a solution to add condition for reference table items in linq.
I have a master table called TourPackage, which include
public class TourPackage{
public int TourID { get; set; }
public string TourName { get; set; }
public List<IncludedItems> IncludedItems { get; set; }
}
Every tour package contain some selected items reference like
public class IncludedItems {
public int TourID { get; set; }
public int IncludedID { get; set; }
public Included Included { get; set; }
}
All included item should have a reference to Included table for lookup reference
public class Included {
public int IncludedID { get; set; }
public string IncludedValue { get; set; }
}
now i have set of IncludedID like [1,2,3], Is it possible to filter TourPackage based on IncludedID.
Thanks in advance
You can use following code
I have sample array(i.e example) which contains ID's we check if current Id(i.e ele.Included.IncludedID) is present in the array of id's.
listex.Where(x => x.IncludedItems.Any(ele => example.Contains(ele.Included.IncludedID))).ToList();
sample:-
int[] example = new int[3];
example[0] = 123;
example[1] = 456;
example[2] = 789;
List<TourPackage> listex = new List<TourPackage>();
List<TourPackage> filterList = listex.Where(x => x.IncludedItems.Any(ele => example.Contains(ele.Included.IncludedID))).ToList();
Have you tried using something like:
var myIds = new List<int> {123,456};
var result = context.TourPackages
.Where(x => x.IncludedItems.Any(a => a.Included !=null && myIds.Contains(a.Included.IncludedId)))
.ToList();
You might have to include some relations manually depending if you're lazy loading is setup or not.
More info at https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx
I have been trying to teach myself Sitecore for the past couple of weeks.
At the moment i am trying to create a list of Recipes for users to search through.
However every Recipe contains Ingredients, Lucene returned these Ingredients as strings containing Item ID's. I wanted to have a List of Ingredients in my code so i gave GlassMapper a shot.
So i excluded the Ingredient list in my code from Lucene by changing the name so Lucene couldn't find the field.
I then set-up GlassMapper to fill the Ingredient list. The list stays null however.
How do i make GlassMapper fill this list for me?
My code:
Recipe class
[SitecoreType(TemplateId= "{1CF86642-6EC5-4B26-B8A7-1B2EC41F7783}")]
public class Recipe : SearchResultItem
{
[SitecoreId]
public Guid Id { get { return base.ItemId.Guid; } }
public virtual string RecipeName { get; set; }
public virtual string BookName { get; set; }
public virtual IEnumerable<Ingredient> _Ingredients { get; set; }
public virtual int AmountOfPeople { get; set; }
}
Ingredient class
[SitecoreType(TemplateId = "{730A0D54-A697-4DAA-908A-279CD24A9F41}")]
public class Ingredient : SearchResultItem
{
[SitecoreId]
Guid Id { get; }
[IndexField("Name")]
public virtual string IngredientName { get; set; }
}
GlassMapperScCustom class (I've only edited this method)
public static IConfigurationLoader[] GlassLoaders()
{
var attributes = new SitecoreAttributeConfigurationLoader("Receptenboek");
var loader = new SitecoreFluentConfigurationLoader();
var config = loader.Add<Recipe>();
config.Id(x => x.ItemId);
config.Info(x => x.Language).InfoType(SitecoreInfoType.Language);
config.Info(x => x.Version).InfoType(SitecoreInfoType.Version);
config.Field(x => x._Ingredients);
config.Info(x => x.Uri).InfoType(SitecoreInfoType.Url);
return new IConfigurationLoader[] {attributes, loader };
}
Recipe Controller
[HttpGet]
public ActionResult Index()
{
List<Recipe> recipes;
IQueryable<Recipe> query;
string index = string.Format("sitecore_{0}_index", Sitecore.Context.Database.Name);
var sitecoreService = new SitecoreService(Sitecore.Context.Database.Name);
string search = WebUtil.GetQueryString("search");
using (var context = ContentSearchManager.GetIndex(index).CreateSearchContext())
{
if (!string.IsNullOrEmpty(search))
{
query = context.GetQueryable<Recipe>().Where(p => p.Path.Contains("/sitecore/Content/Home/Recipes/")).Where(p => p.TemplateName == "Recipe").Where(p => p.RecipeName.Contains(search));
}
else
{
search = "";
query = context.GetQueryable<Recipe>().Where(p => p.Path.Contains("/sitecore/Content/Home/Recipes/")).Where(p => p.TemplateName == "Recipe");
}
recipes = query.ToList();
foreach( var r in recipes)
{
sitecoreService.Map(r);
Sitecore.Diagnostics.Log.Audit("SWELF" + r.RecipeName + "- " + r.BookName + " - " + r.AmountOfPeople + " - " + r.Name + "--" + r._Ingredients.Count(), this);
}
}
RecipesViewModel bvm = new RecipesViewModel() { Recipes = recipes, Search = search };
return View(bvm);
}
After playing around for a while i decided to split my search and mapping a little more. I used my Recipe model with Lucene and created a ViewModel to map the fields to with GlassMapper.
The Recipe class did not change.
The Ingredient class did not change.
The GlassMapperScCustom class was not needed so i restored its default.
RecipeViewModel class
After mapping to this class the Ingredient list had the correct amount of ingredients however all its fields where null.
After looking around on the internet a little more i found this stackoverflow post: Why isn't my Enumerable getting populated by Glass.Mapper?
I decided to give the SitecoreFieldType a go and it did the trick!
[SitecoreType(TemplateId = "{1CF86642-6EC5-4B26-B8A7-1B2EC41F7783}", AutoMap = true)]
public class RecipeViewModel : BaseFields
{
[SitecoreId]
public ID Id { get; set; }
public virtual string RecipeName { get; set; }
public virtual string BookName { get; set; }
[SitecoreField(FieldId = "{D1603482-7CBC-4E55-9CCB-E51DC0FC5A0B}", FieldType = SitecoreFieldType.Multilist)]
public virtual IEnumerable<IngredientViewModel> Ingredients { get; set; }
public virtual int AmountOfPeople { get; set; }
}
Recipe Controller
It turned out to be mapping the wrong way aswel. I found an example of a list being mapped to another list using SitecoreService.GetItem<>()
[HttpGet]
public ActionResult Index()
{
List<RecipeViewModel> recipes;
List<Recipe> query;
string index = string.Format("sitecore_{0}_index", Sitecore.Context.Database.Name);
var sitecoreService = new SitecoreService(Sitecore.Context.Database.Name);
string search = WebUtil.GetQueryString("search");
//Search with Lucene
using (var context = ContentSearchManager.GetIndex(index).CreateSearchContext())
{
if (!string.IsNullOrEmpty(search))
{
query = context.GetQueryable<Recipe>().Where(p => p.Path.Contains("/sitecore/Content/Home/Recipes/")).Where(p => p.TemplateName == "Recipe").Where(p => p.RecipeName.Contains(search)).ToList();
}
else
{
search = "";
query = context.GetQueryable<Recipe>().Where(p => p.Path.Contains("/sitecore/Content/Home/Recipes/")).Where(p => p.TemplateName == "Recipe").ToList();
}
}
//Map to ViewModel
recipes = query.Select(x => sitecoreService.GetItem<RecipeViewModel>(x.ItemId.Guid)).ToList();
RecipesViewModel bvm = new RecipesViewModel() { Recipes = recipes, Search = search };
return View(bvm);
}
One more problem
Because my ViewModel does not inherit from SearchResultItem a lot of useful fields where lost in the mapping. To keep the fields I needed from the SearchResultItem I made a BaseFields class for my ViewModel to inherit. I only needed Url for now but this can be easily expanded with more fields.
public class BaseFields
{
public virtual string Url { get; set; }
}
I have the following query:
IQueryable<BarcodeQuery> barcodes = db.Barcodes.Select(b => new BarcodeQuery
{
id = b.id,
category_id = b.category_id,
...
checkout = b.Checkouts.Select(c => new CheckoutChild
{
id = c.id,
loanee_id = c.loanee_id,
...
})
.Where(c => c.datein == null)
.FirstOrDefault()
});
And so on. It's based on this model:
public class BarcodeQuery
{
public int id { get; set; }
public int category_id { get; set; }
...
public CheckoutChild checkout { get; set; }
public CheckoutStatus checkoutStatus { get; set; }
}
My question is about CheckoutStatus down there at the bottom. It looks like this:
public class CheckoutStatus
{
public string status { get; set; }
public int daysUntilDue { get; set; }
public int daysOverdue { get; set; }
}
All of those values are derived from information I get from the query--none of them are in the database itself. What is the best way of inserting the CheckoutStatus values into each barcode record?
I have a function that creates the CheckoutStatus values themselves, I just don't know how to get them into the barcode records.
Thanks!
If b has just be created with new, how can b.Checkouts contain something? I do not really understadn what you are trying to do.
EF is converting the lambda expression into a SQL statement. Therefore you can only use expressions that can actually be translated to SQL. Just query the barcodes from the DB and then add the missing information to the barcodes returned in a loop.
var barcodes = db.Barcodes.Select(...).ToList();
foreach (Barcode b in barcodes) {
b.Checkouts = ...
}
I'm extremely new to ASP .NET and LINQ so please forgive me for my ignorance.
I've a Region class:
public class Region
{
[Key]
public int Region_ID { get; set; }
public string Region_Name { get; set; }
}
And a Service class:
public class Service
{
[Key]
public int Service_ID { get; set; }
public string Service_Name { get; set; }
}
And a mapping class which stores the many-many mapping of service_IDs with region_IDs:
public class Mapping_ServiceToRegion
{
[Key]
public int Service_ID { get; set; }
public int Region_ID { get; set; }
}
Now I want to create an API function which outputs Region_Name based on given Service_ID. This is what I have so far in my RegionsController:
// GET api/Regions/Service_ID
[ResponseType(typeof(Region))]
public async Task<IHttpActionResult> GetRegion(int id)
{
var region_id = from sr in db.Mapping_ServiceToRegions
where sr.Service_ID == id
select sr.Region_ID;
var region = await db.Regions.Select(r =>
new Region()
{
Region_ID = r.Region_ID,
Region_Name = r.Region_Name
}).SingleOrDefaultAsync(r => r.Region_ID == region_id); //ERROR
if (region == null)
{
return NotFound();
}
return Ok(region);
}
The error I'm getting is:
Cannot convert lambda expression because it is not a delegate type.
I realize that my region_id variable will have multiple region_ids based on a service_id. How can I modify the code to account for this? Is there an IN operator that I can use to say r.Region_ID IN region_id?
And does the above code look correct otherwise?
Thanks.
You should change the SingleOrDefaultAsync() call using Contains() method like below since your region_id is of IEnumerable<T> and not a single value and so you can't perform direct equality comparison.
SingleOrDefaultAsync(r => region_id.Contains(r.Region_ID))
Ahh!!! here Region is one of EF mapped entity and you are trying to construct that and thus the error. You should either chose to select an Anonymous type (or) use a custom viewmodel/DTO object like
var region = await db.Regions.Select(r =>
new
{
Region_ID = r.Region_ID,
Region_Name = r.Region_Name
}).SingleOrDefaultAsync(r => region_id.Contains(r.Region_ID));