Get another class from LINQ to SQL query - c#

I am a little weak in LINQ to SQL so will try to explain my problem.
I have a method as follows (simplified to explain it better):
public static List<ic_ProductData> GetCompleteSimilarProductsWithApplyButton(InfoChoiceAdminDataContext db)
{
var products = (from
p in db.ic_ProductDatas
join proddef in db.ic_ProductDefs on p.ProductDefId equals proddef.ProductDefId
select p
).ToList();
return products;
}
ic_ProductData and ic_ProductDefs are tables in my database
The ic_ProductData class contains a manually created property as:
public ic_ProductDef RelatedProductDef { get; set; }
I want to modify the above LINQ to SQL query so that I can populate this property.
Please note I do not want another call to the database.
Also there are a lot of properties in ic_ProductData so I want to avoid mapping each and every property
Something to the effect of the following (obviously the below is wrong):
public static List<ic_ProductData> GetCompleteSimilarProductsWithApplyButton(InfoChoiceAdminDataContext db)
{
var products = (from
p in db.ic_ProductDatas
join proddef in db.ic_ProductDefs on p.ProductDefId equals proddef.ProductDefId
//trying to change here
select new ic_ProductData
{
//do something with p here so that all the properties of new object gets filled
// avoid mapping of properties here
RelatedProductDef = proddef
}
).ToList();
return products;
}
With my limited knowledge I am stuck here.
Please help!
Thanks in advance!

You can do something like this:
var query = (from p in db.ic_ProductDatas
join proddef in db.ic_ProductDefs on p.ProductDefId equals proddef.ProductDefId
select new
{
ProductData = p,
Def = proddef
}).ToList();
List<ic_ProductData> products = new List<ic_ProductData>();
foreach( var product in query)
{
product.ProductData.RelatedProductDef = product.Def;
products.Add(product);
}
Basicly, you first need to do the one query to the database, this returns an anonymous type containing both your product and its Def.
Finally, you loop (in memory, no db-calls!) over these, creating your final objects with their RelatedProductDef properties populated.

Related

C# Loading collection on viewModel

I have a viewmodel that has a header property, and then an associated child collection as such:
public int ProjectApprovalHeaderId { get; set; }
public List<ProjectApprovalStepsVM> ProjectApprovalHistorySteps{ get; set; }
I have a query that returns the data as follows:
ProjectApprovalHeaderId StepName Status
1 Step1 A
1 Step2 C
1 Step3 A
2 Step1 D
I'm trying to write the LINQ so that I can populate the viewmodel with the HeaderId and then the child collection with the actual step data but I'm stuck. I know this isn't much, but it's where I'm at:
var approvalHistory = from s in _context.ProjectApprovalSteps
join u1 in _context.Users on s.AssignedApproverID equals u1.ID
join p in _context.Projects on s.ProjectID equals p.ID
join sc in _context.ApprovalStepStatusCodes on s.Status equals sc.StatusCode into statusList
from scd in statusList.DefaultIfEmpty()
where s.ProjectID == projectId
orderby s.ProjectApprovalHeaderID, s.Sequence
select new ProjectApprovalHistoryVM
{
ProjectApprovalHeaderId = s.ProjectApprovalHeaderID,
ProjectApprovalHistorySteps =
};
vmApprovalHistory.ProjectApprovalHistorySteps = approvalHistory.ToList();
Hoping someone can point me in the right direction.
I'm a fan of Dapper, you can install via Nuget Install-Package Dapper. The reason I recommend, is the multi mapping capabilities. So an object like you have, has nested objects that are needed to be populated and filtered.
public IEnumerable<SpeciesModel> GetAllSpecies() => dbConnection
.Query<SpeciesModel, SpeciesCategoryModel, SpeciesTypeModel, WetlandIndicatorModel, SpeciesModel>(getAllSpeciesQuery,
(species, speciesCategory, speciesType, wetlandIndicator) =>
{
species.SpeciesCategory = speciesCategory;
species.SpeciesType = speciesType;
species.WetlandIndicator = wetlandIndicator;
return species;
});
So the above syntax is expressing the nested object. As your query is returned, it'll also associate your child objects. I believe that is your intent, plus this saves you a lot of time.
More complex example with a collection as a nested object with Dapper.
public IEnumerable<StemModel> GetStemModelForPlotHeader(int projectParameter, int plotParameter,
string plantCommunityParameter) =>
dbConnection.Query<StemModel, PlotSurveyModel, PlantCommunityModel, ProjectModel, SpeciesModel, StemModel>(getAllPlotHeaderDetails,
(stem, survey, plantCommunity, project, species) =>
{
stem.PlotSurvey = survey;
survey.PlantCommunity = plantCommunity;
survey.Project = project;
stem.Species = species;
return stem;
},
new
{
ProjectId = projectParameter,
PlantCommunityCode = plantCommunityParameter,
PlotNumber = plotParameter
});
Update:
Please note the above answer would require you to replace your data access layer. I'm impartial to Dapper, since you receive the performance with the extra mapping functionality. Especially for simple queries, but you can leverage the performance with extra mapping capabilities. Also it forces your data calls to be SQL oriented, not code generating dynamic queries.

returning multiple class model data from linq in list via return method in C#

I have LINQ output which I am trying to pass in list but I am getting following error
in linq result I am trying to pass data from two class model, if I do one class model (listOfCoursesWithoutURL ) then it work but I need to pass processedCourseInstance. I have created ModelView of two classes but not sure what I am missing in this picture
ViewModel
public class CoursesInstanceStudyLevel_ViewModel
{
public CourseInstanceModel _CourseInstanceModel { get; set; }
public StudyLevelModel _StudyLevelModel { get; set; }
}
My Class
public List<CoursesInstanceStudyLevel_ViewModel> ProcessAllCoursesApplicationURL(CourseApplicationsURLFeed_Model _obj)
{
using(var _uof = new Courses_UnitOfWork())
{
_uof.CourseInstances_Repository.GetAll();
var _listOfCoursesWithoutURL = (from b in ListOfCoursesInstances
where b.ApplicationURL == null
select b).ToList();
var processedCourseInstance = (from _courseInstances in _uof.CourseInstances_Repository.GetAll()
join _courses in _uof.Courses_Repository.GetAll() on _courseInstances.CourseID equals _courses.CourseID
join _studylevel in _uof.StudyLevel_Repository.GetAll() on _courses.StudyLevelId equals _studylevel.StudyLevelID
orderby _courseInstances.CourseCode
select new { _courseInstances, _studylevel }).ToList();
return processedCourseInstance; // it doesn't work ... refer to screen shot
// return _listOfCoursesWithoutURL //it works
}
}
Error
here:
select new { _courseInstances, _studylevel })
you are defining an anonymous object. You have a type ready, so use that one:
select new CoursesInstanceStudyLevel_ViewModel
{
_CourseInstanceModel = _courseInstances,
_StudyLevelModel = _studylevel
}
assuming CourseInstanceModel and StudyLevelModel are the correct types
With highlighted line in following code snippet, you are selecting an anonymous object instead of a concrete CourseIntaceStudyLeve_ViewModel
select new { _courseInstances, _studylevel }
You will have to change your query to following..
var processedCourseInstance = (from _courseInstances in _uof.CourseInstances_Repository.GetAll()
join _courses in _uof.Courses_Repository.GetAll() on _courseInstances.CourseID equals _courses.CourseID
join _studylevel in _uof.StudyLevel_Repository.GetAll() on _courses.StudyLevelId equals _studylevel.StudyLevelID
orderby _courseInstances.CourseCode
select new CoursesInstanceStudyLevel_ViewModel(){
_CourseInstanceModel = _courseInstances.FirstOrDefault(),
StudyLevelModel = _studylevel.FirstOrDefault()}).ToList();
I have assumed you would need only first course and first study level based on your view model definition and there for applied FirstOrDefault. You can choose to go along with this or change your view model definition.
here is my answer and it works
var processedCourseInstance =
(from _courseInstances in _uof.CourseInstances_Repository.GetAll()
join _courses in _uof.Courses_Repository.GetAll() on _courseInstances.CourseID equals _courses.CourseID
join _studylevel in _uof.StudyLevel_Repository.GetAll() on _courses.StudyLevelId equals _studylevel.StudyLevelID
orderby _courseInstances.CourseCode
select new CoursesInstanceStudyLevel_ViewModel() {
_CourseInstanceModel = _courseInstances,
_StudyLevelModel = _studylevel
}).ToList();

Referencing a row from another table c# linq

I want to use an id from one table to list a title from another table in wpf, so i did this:
var q = from a in context.associations
select a;
associations = q.ToList();
associationViewSource.Source = associations;
foreach (var item in q)
{
var qTitles = from b in context.textbooks
where b.Id == item.book_id
select b.Title;
assocListView.ItemsSource = qTitles.ToList();
}
in the first portion of the code i am making the main body of the information, it lists all the information from associations table, after that i want to list the relevant titles from textbooks table, thats where i add items to the assocListview, but it of course fails and the data isn't displayed, no errors are thrown either. i hope i was clear enough.
Please help
You can get a list of Titles that have associations with a join...
var qTitles = context.textbooks
.Join(context.associations,
b => b.Id,
a => a.book_id,
b => b.Title)
.ToList();
The intention of the code isn't clear though because assocListView.ItemsSource is assigned to in each iteration of the loop. Is that a bug?
Since you are setting assocListView.ItemsSource each pass through the loop, the resultant list will have the results of the last query.
If you want a list of all associated titles you can get it with a single query:
var titles =
from a in context.associations
join b in context.textbooks on a.book_id equals b.Id
select b.Title;
assocListView.ItemsSource = titles.ToList();
This will return every title linked to any record in your associations table, in no particular order, with duplicates, etc. Normally it makes sense to extract a little more information to make it more usable. For instance, define a structure to hold an associated title:
public struct AssocTitle
{
public int AssocID;
public int BookID;
public string Title;
}
Then query it like:
var titles =
from a in context.associations
join b in context.textbooks on a.book_id equals b.Id
select new AssocTitle { AssocID = a.Id, BookID = b.Id, Title = b.Title };
Then when you click on things in the list view you can find out which book and which association, even if you have lots of associations with the same titles.

How to add to linq2sql entity set for master detail if I can't explicitly define the detail?

Maybe I'm going about this the wrong way...
I have an Order table and an OrderItem table. I create a new Order using linq2sql generated classes.
I then attempt to get all orderable items out of my database using a query that goes after various tables.
I try to then create a new list of OrderItem from that query, but it squawks that I can't explicitly create the object.
Explicit construction of entity type OrderItem in query is not allowed.
Here is the query:
return (from im in dc.MasterItems
join c in dc.Categories
on im.CATEGORY equals c.CATEGORY1
select new OrderItem()
{
OrderItemId = im.ItemId
});
The idea is to populate the database with all orderable items when a new order is created, and then display them in a grid for updates. I'm taking the results of that query and attempting to use AddRange on Order.OrderItems
Is there a proper strategy for accomplishing this using linq2sql?
Thanks in advance for your help.
From my understanding of L2S, I don't think you can use explicit construction (in other words new SomeObj() { ... }) in a query because you aren't enumerating the results yet. In other words, the query has just been built, so how are you supposed to do this:
SELECT new OrderItem() FROM MasterItems im JOIN Categories c on c.CATEGORY1 = im.CATEGORY
This is what you're trying to do, which doesn't work because you can't return a POCO (unless you join the OrderItem back somehow and do OrderItem.* somewhere). Ultimately, what you would have to do is just enumerate the collection (either in a foreach loop or by calling ToList()) on the query first and then build your OrderItem objects.
var query = (from im in dc.MasterItems
join c in dc.Categories
on im.CATEGORY equals c.CATEGORY1
select new { MasterItem = im, Category = c});
List<OrderItem> returnItems = new List<OrderItem>();
foreach(var item in query)
{
returnItems.Add(new OrderItem() { OrderItemId = item.MasterItem.ItemId });
}
return returnItems;
OR
return (from im in dc.MasterItems
join c in dc.Categories
on im.CATEGORY equals c.CATEGORY1
select new { MasterItem = im, Category = c})
.ToList()
.Select(tr => new OrderItem() { OrderItemId = tr.MasterItem.ItemId });
Try that out and let me know if that helps.
Expand the order class by creating a partial file where that class OrderItem now has property(ies) which lend itself to business logic needs, but don't need to be saved off to the database.
public partial class OrderItem
{
public int JoinedOrderItemId { get; set; }
public bool HasBeenProcessed { get; set; }
}

Returning DB Query Result as List in a WebService

im trying to return a list in a web service method with the results of some db queries.
My Query is:
var Address = (from table in Model.Table where *-some conditions and join clause-* select Address).Firstordefault();
var Phone =(from table in Model.Table where *-some conditions and join clause-* select Phone).FirstOrDefault();
Web Service Method:
[WebMethod]
public List< x> ShowDetails(*input parameters*)
{
List< x> list = new List<x>();
list.Add(Address);
list.Add(Phone);
return list;
}
My question is how can i define the List< x> elements with my query results?
I don't see the reason to use a list here. Simple solution is create a custom class to save both result:
public class X
{
public Address Address{get;set;}
public Phone Pnone {get;set;}
}
And then you can do the following:
[WebMethod]
public X ShowDetails(*input parameters*)
{
var address = Model.Addresses.FirstorDefault(some conditions);
var phone = Model.Phones.FirstorDefault(some conditions);
return new X{Address=address, Phone=phone};
}
Now I see that you mention you are also joining tables probably to apply some conditions. I suggest you instead of that you use navigation properties,eg:
var address = Model.Addresses.FirstorDefault(a=>a.State.StateId==9);
That query is going to do the join for you once it's translated to sql.

Categories