Select Entity property in related table using linq - c#

here is my setup.
Base Model
public class Base
{
public int BaseID { get; set; }
[StringLength(8)]
[Index(IsUnique = true)]
public string BaseNumber { get; set; }
public ICollection<BillOfMaterial> billOfMaterials { get; set; }
}
BillOfMaterial Model
public class BillOfMaterial
{
public int BillOfMaterialID { get; set; }
[StringLength(10)]
[Index(IsUnique = true)]
public string BomNumber { get; set; }
public ICollection<Base> Bases { get; set; }
}
What I am trying to do is select all bill of material BomNumbers where the base is equal to a input base number.
What I have tried
BaseNumber = "A1C1D001";
var BOMQuery = (from Base in db.Bases.Include("BillOfMaterials")
where Base.BaseNumber == BaseNumber
select Base.billOfMaterials.ToList());
When trying to create this query I can't see the BomNumber property when I do => select Base.BillOfMaterials.(Can't Find Property)
I tried using the .Include() extension to try and bring in the related table in hopes it would give me the property. Not sure how to word this question exactly to do a good google search for the answer. What am I doing wrong here? Any help would be appreciated.
Thank you,

When you only need a list of BOMs use the following:
var BOMQuery = db.Bases
.Where(x => x.BaseNumber == BaseNumber)
.SelectMany(a => a.billOfMaterials.Select(b => b.BomNumber)).ToList();
You can then add it to an ObservableCollection like this:
BomList = new ObservableCollection<string>(BOMQuery);

Related

Entity Framework using Load with Select - is it possible?

I'm trying to optimize my EF queries and I'm stuck with this one.
Let's say I have a model like this:
public class House
{
public int ID { get; set; }
public ICollection<Window> Windows { get; set; }
}
public class Window
{
public int ID { get; set; }
public string Color { get; set; }
public WindowKind Kind { get; set; }
}
public class WindowKind
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
What I would like to do is to explicitly load all windows and to specify what should be populated in WindowKind property.
I know I can do it with .Include() like this:
var house = Context.Houses.Single(h => h.ID == id);
var windows = Context.Entry(house).Collection(h => h.Windows).Query().Include(w => w.Kind).Load();
However, this will create a query that will load all WindowKind properties and I need only Name, for example. I was hoping something like this would work but it does not, Windows collection is empty, although the generated query looks good.
var house = Context.Houses.Single(h => h.ID = id);
var windows = Context.Entry(house).Collection(h => h.Windows).Query().Select(w => { new w.Color, w.Kind.Name }).Load();
Is it possible to have fine grained control when loading child collections?
you can't load only a part of the scalar (int, string,...) properties of an entity by loading the entity.
In you case, something like the following should do:
from
w in Context.Windows
where
w.House.ID == id // here a navigation property is missing, but (imho) more clear for the sample
select new {
windows = w,
kName = w.Kind.Name
}
But in this case you will not get context attached entities.

ravendb index across multiple nested properties

I am asking how to create an index based upon two different nested properties on an document. I am executing these queries through C#.
public class LocationCode
{
public string Code {get;set;}
public string SeqId {get;set;}
}
public class ColorCode
{
public string Code {get;set;}
public string SeqId {get;set;}
}
public class TestDocument
{
public int Id {get;set;}
public List<LocationCode> Locations { get; set; }
public List<ColorCode> Colors { get; set; }
}
I have experimented with various AbstractIndexCreationTask, Map, and Map+Reduce, but to no avail.
I would like to be able to do a query such as:
Get all documents where any Locations.Code property is "USA", AND/OR Colors.Code="RED", or on the SeqId property. I dont know whether this would mean I need multiple indexes. Normally I would either be comparing the Code property on both nested classes, or the Seq, but never mixed.
Please could someone point me in the right direction.
Many thanks
Phil
Create your index like this:
public class TestIndex : AbstractIndexCreationTask<TestDocument, TestIndex.IndexEntry>
{
public class IndexEntry
{
public IList<string> LocationCodes { get; set; }
public IList<string> ColorCodes { get; set; }
}
public TestIndex()
{
Map = testDocs =>
from testDoc in testDocs
select new
{
LocationCodes = testDoc.Locations.Select(x=> x.Code),
ColorCodes = testDoc.Colors.Select(x=> x.Code)
};
}
}
Then query it like this:
var q = session.Query<TestIndex.IndexEntry, TestIndex>()
.Where(x => x.LocationCodes.Any(y => y == "USA") &&
x.ColorCodes.Any(y => y == "RED"))
.OfType<TestDocument>();
Full unit test here.

Entity Framework (5.0) Code First - Insert into Collection within Collection

I've got three classes.
Event > Workshop > Workshop Times
I'm currently looking for best way of inserting records into the Workshop Times, this is running through code first using ICollections.
Looking for something along the lines of this, but I know it doesn't work:
//Create connection
var db = new Context();
var Event = db.Events
.Include("Workshops")
.Include("Workshops.Times")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Event.Workshops.Add(new Workshop
{
Name = tbWorkshopName.Text,
Description = tbWorkshopDescription.Text,
Times.Add(new WorkshopTime{
//Information for times
})
});
db.SaveChanges();
Chopped down classes:
public class Workshops{
public int id { get; set; }
public string name { get; set; }
public ICollection<WorkshopTimes> Times{get;set;}
}
public class Events {
public int id { get; set; }
public string name { get; set; }
public ICollection<Workshops> WorkShops { get; set; }
}
public class WorkshopTimes {
public int id { get; set; }
public DateTime time { get; set; }
}
You are definitely on the right track with your query, however your include statements appear incorrect. From your model I would expect:
var Event = db.Events
.Include("WorkShops")
.Include("WorkShops.events")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Note this uses the property names not the types. This will ensure that the entities in the listed nav properties will be included in the result.
In addition you can use a lambda to do the same thing (but its typesafe)
Check out here for how to do a very similar scenario to yours:
EF Code First - Include(x => x.Properties.Entity) a 1 : Many association
or from rowan miller (from EF team)
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
And make sure you are using System.Data.Entities for lambda based includes ( Where did the overload of DbQuery.Include() go that takes a lambda? )

How to move string into ViewModel

I am creating a new ViewModel that tally's up the results of a survey, performers some calculations on that data, and then returns the new calculation to a view. I cannot figure out how to include regular "string" data in the collection.
var data = from SurveyResponseModel in db.SurveyResponseModels
group SurveyResponseModel by SurveyResponseModel.MemberId into resultCount
select new ResultsViewModel()
{
MemberId = resultCount.Key,
UseNewTreatmentResult = db.SurveyResponseModels.Count(r => r.UseNewTreatment),
UseBetterTechniqueResult = db.SurveyResponseModels.Count(r => r.UseBetterTechnique),
ChangesOthersResult = db.SurveyResponseModels.First(r => r.ChangesOthers),
};
return View(data);
The first part is counting boolean responses and passing them as an integer back to the ViewModel. The section that includes ChangesOthersResult = db.SurveyResponseModels.First(r => r.ChangesOthers), Should just select the strings from the Model and pass to the ViewModel. I am currently getting a syntax error about changing from type string to bool. I'm not sure what the syntax for this is.
public class SurveyResponseModel
{
[Key]
public int ResponseId { get; set; }
public int MemberId { get; set; }
public int ProgramId { get; set; }
[DisplayName("Use a new treatment")]
public bool UseNewTreatment { get; set; }
[DisplayName("Use better/more updated technique")]
public bool UseBetterTechnique { get; set; }
[DisplayName("Other (please specify):")]
public string ChangesOthers { get; set; }
}
public class ResultsViewModel
{
public int MemberId { get; set; }
public int ProgramId { get; set; }
[DisplayName("Use a new treatment")]
public int UseNewTreatmentResult { get; set; }
[DisplayName("Use better/more updated technique")]
public int UseBetterTechniqueResult { get; set; }
[DisplayName("Other (please specify):")]
public string ChangesOthersResult { get; set; }
}
You need:
ChangesOthersResult = db.SurveyResponseModels.Select(r => r.ChangesOthers)
Or SelectMany. Eventually add FirstOrDefault() at the end depending on what type ChangesOthersResult is and what you actually want to select.
Select gives you a "collection of collections" (I am assuming that ChangesOthers is a collection type). SelectMany a "flattened collection" of the generic type of your ChangesOthers collection. Adding FirstOrDefault() after Select gives you the single collection of the first SurveyResponseModels entity - or null.
Edit
After you supplied the classes I see that ChangesOthers and ChangesOthersResult aren't collections but just of type string. So the line should be:
ChangesOthersResult = db.SurveyResponseModels.Select(r => r.ChangesOthers)
.FirstOrDefault()

MVC3 linq joins

As a novice am trying my hands on MVC3,razor, EF I have Three connected Tables that I want to produce a view from it. In a simpleton's brief the following are about the tables
PJUsers - ID, memUID(this unique Id from membership),FirstName,LastName
PJAwards - user nominates another user for an award, this links with awardtypesID as foreign key ( awardId,bool:awardok)
PJAwartypes - (awardtypeID, awardName)
The query in the controller is like this
var lists =
from tl in db.PJawards
join u in db.PJUsers on tl.nomineeId equals u.ID into tl_u
join i in db.PJUsers on tl.nominatorId equals i.MemUID into tl_i
where tl.awardOk
orderby tl.awardDated ascending
from u in tl_u.DefaultIfEmpty()
from i in tl_i.DefaultIfEmpty()
select new
{
Status = tl.awardOk,
nomineeFname = u.FirstName,
nomineeLname = u.LastName,
award = tl.PJawards.awardName,
Dated = tl.awardDated,
nominatorFname = i.FirstName,
nominatorLname = i.LastName,
nomineeCountry = u.Citizen,
nomineeResidence = u.Residence,
awardtypeId = tl.ID
};
somewhere i read that i have to construct a model class similar to the query in the controller
{
public class AwardUserInfo
{
public AwardUserInfo() { }
public bool Status { get; set; }
public string nomineeFname { get; set; }
public string nomineeLname { get; set; }
public string award { get; set; }
public string Dated { get; set; }
public string nominatorFname { get; set; }
public string nominatorLname { get; set; }
public string nomineeCountry { get; set; }
public string nomineeResidence { get; set; }
public int awardtypeId { get; set; }
}
}
Please I learn by examples so to be able to help me assume I don't know anything
somewhere i read that i have to construct a model class similar to the query in the controller
Try this.
I guess your ef-model is similar to
So You can create a ViewModel class
public class PJAwardsViewModel
{
public int Id { get; set; }
public string NominatorFName { get; set; }
public string NomineeFname { get; set; }
public string AwardName { get; set; }
public bool IsAwarded { get; set; }
}
It will be also good if You add some service class
public class PJAwardsService
{
public static List<PJAwards> GetAll()
{
using (var context = new YourDBEntities())
{
return context.PJAwards
.Include(x => x.PJUsers)
.Include(x => x.PJUsers1)
.Include(x => x.PJAwartypes).ToList();
}
}
}
(Don't forget to write using System.Data.Entity; )
Then You can add a ViewModelHelper class
public class PJAwardsViewModelHelper
{
public static PJAwardsViewModel PopulatePJAwardsViewModel(PJAwards pjaward)
{
return new PJAwardsViewModel
{
Id = pjaward.Id,
NominatorFName = pjaward.PJUsers.FirstName,
NomineeFname = pjaward.PJUsers1.FirstName,
AwardName = pjaward.PJAwartypes.AwardName,
IsAwarded = pjaward.IsAwarded
};
}
public static List<PJAwardsViewModel> PopulatePJAwardsViewModelList(List<PJAwards> pjawardsList)
{
return pjawardsList.Select(x => PopulatePJAwardsViewModel(x)).ToList();
}
}
At the end Your controller index method will look like this
public ActionResult Index()
{
var pjawards = PJAwardsViewModelHelper.PopulatePJAwardsViewModelList(PJAwardsService.GetAll().ToList());
return View(pjawards);
}
The only thing You should do is add a view (build the project before). Choose PJAwardsViewModel as a Model class and List as a scaffold template.
Enjoy it.
Here is a step by step guide by Steven Sanderson on how to use Asp.net MVC3, EF Code First with MVCScaffolding (powershell automation).
http://blog.stevensanderson.com/2011/01/13/scaffold-your-aspnet-mvc-3-project-with-the-mvcscaffolding-package/
It is a multipart blog post takes you through the exciting journey of MVC3.
All the best.

Categories