Is it possible to access the parent of a Linq object? - c#

In a situation where an EntitySet is being queried (in, say, a many-to-many relationship), is it possible to access the parent object?
e.g
Thing thing = db.Things.First();
Widget widget = thing.Widgets.First();
// Let's assume that Widgets can have many things as well
// (i.e. widget.Things is possible)
widget.ParentThing // would return the same instance of thing used above
Is that possible?

is it possible to access the parent object
With a many-to-many there really isn't a "parent" - there are multiple related objects. A many-to-many is usually modeled with navigation properties:
public class Thing
{
public int ID {get; set;}
public virtual IEnumerable<Widget> Widgets {get; set;}
}
public class Widget
{
public int ID {get; set;}
public virtual IEnumerable<Thing> Things {get; set;}
}
If your model doesn't have such properties then an alternative is to go back to the context (or back to the db if you don't have the context anymore):
var relatedThings = db.Things
.Where(t => t.Widgets.Any(w => ID == widget.ID));

Related

EF Generic Repository Pattern - Insert/Create Method Issue While Inserting Root Entity with Sub Entities

public class A
{
string Id {get; set;}
string Property_1 {get; set;}
string Property_2 {get; set;}
// Foreign Key for Class B
string B_Id {get; set;}
// Many to One Relationship
B objectOfClassB {get; set;}
// One to Many Relationship
ICollection<objectOfClassC> listOfClassC {get; set;}
}
We have an Object of Class A, that we are trying to insert. We are also passing Values for Class B & Class C (List) which are sub entity of Class A.
While inserting, we want to check first whether sub-entity i.e. values of ObjectofClassB is not present in the database table. If it is present just add the Foreign Key of the same to Class A Table.
So how could we prevent Detaching or Not Inserting only objectOfClassB (sub-entity)?
Note - I want to insert listOfClassC (another sub-entity)
First you check whether there is B Class in the Database
ex:
var b = dbContext.B.FirstOrDefault()
if(b != null)
{
A.objectOfClassB = b;
//.. do something else or persist
}
For adding the collection objectOfClassC
just add it to A.listOfClassC and when you add
"A" to the db EF will create objectOfClassC entities in the DB for you.

C# Automapper Nested Object

Ive searched for this for few days now and cant seem to get anything to work, I am using c# MVC Entity Framework with Automapper and im trying to achieve the below ViewModels (mainly LostDocumentVM) to be mapped from my database, all other properties will be set in controllers.
Here is my ViewModels...
DocumentVM
{
Public Enum.HistoricType HistoricType {get;set;}
Public DocumentChildVM Document { get; set;}
}
DocumentChildVM
{
Public bool ShowHistoricLink {get;set;}
Public IEnumerable<ListDocumentVM> DocumentsToReview {get;set;}
}
ListDocumentVM
{
Public int Id {get;set;}
Public string Name {get; set;}
Public DateTime? ReviewDate {get;set;}
}
I initialise the DocumentVM like this...
DocumentVM documentVM = DataContext.SystemUser.Where(x=>x.SustemUserID==LoggedOnUserID).Project().To<DocumentVM>().SingleOrDefault();
And my mapping is like this...
Mapper.CreateMap<SystemUser,DocumentVM>()
.ForMember(dest=>dest.Document.DocumentsToReview, opt=>opt.MapFrom(src=>src.Documents.Where(x=>x.DocumentType == Enum.DocumentType.Assessment));
Im new to AutoMapper and struggling to get more advanced mappings to work.
Yes, your ForMember member must refer to a member on the destination type, and yours is referring to a member on the child type. Instead, you'll need to create an AfterMap function that fills in this information on that child entity.
It's not difficult, but you have a bit of a strange set up where a child object Document has a property DocumentsToReview from another property on the parent DocumentVM:
documentVM.Document.DocumentsToReview =
src.Documents.Where(doc => doc.DocumentType == Enum.DocumentType.Assessment);
When you have to shuffle data between sibling/nephew members, it gets a little more challenging.
To do this with AfterMap:
Mapper.CreateMap<SystemUser, DocumentVM>()
.AfterMap((src, dest) => dest.Document.DocumentsToReview =
src.Documents.Where(doc => doc.DocumentType == Enum.DocumentType.Assessment));

Entity Framework - Navigation Properties Not Saving

I'm having huge difficulties getting my navigation properties to work in EF Code First. As an abstracted example, I have:
public class Parent{
public int ParentID {get; set;}
public virtual List<NamedChild> Children {get; set;}
public Parent(){}
public void Init(int ParentID, List<UnnamedChild> Children){
this.ParentID = ParentID;
this.Children = Children.ConvertAll(x => new NamedChild(x, ""));
}
}
public class NamedChild{
public int ChildID {get; set;}
public string Name {get; set;}
public NamedChild(UnnamedChild c, string Name){
this.ChildID = c.ChildID;
this.Name = Name;
}
}
public class UnnamedChild{
public int ChildID {get; set;}
public UnnamedChild(int ChildID){
this.ChildID = ChildID;
}
}
and then later...
List<UnnamedChild> children = GetChildrenFromSomewhere();
Parent p = db.Parents.Create();
p.Init(1, children);
db.Parents.Add(p);
db.SaveChanges();
Now if I'm debugging I can look into the current DbSet and it shows that there is 1 Parent, and its "Children" property is set to a List of 2 NamedChild. This is good, this is what it should be. However, if I stop the program and re-run it, when I look in the DbSet there is still 1 Parent, but its "Children" property has been set to null.
In summary, immediately after saving it the values are right, but as soon as I re-load the DB Context those values are missing (nulls). I am running the most recent EF with LazyLoading enabled.
It should be noted that if I use .Include(), it will populate those null values with the proper NamedChild list, but I need this to work with LazyLoading.
I think EF is probably unable to create a proxy for NamedChild objects, and can't perform any lazy loading as a result.
One of the requirements for creating a proxy class is that your POCO must have a public/protected constructor without parameters.
This may solve your problem:
public class NamedChild
{
public int ChildID {get; set;}
public string Name {get; set;}
protected NamedChild() {}
public NamedChild(UnnamedChild c, string Name)
{
this.ChildID = c.ChildID;
this.Name = Name;
}
}
I believe you already meet all the other requirements for lazy loading proxies.
Full Requirements here:
http://msdn.microsoft.com/en-us/library/vstudio/dd468057%28v=vs.100%29.aspx
Although I don't think it should technically matter, I've noticed that EF seems to prefer ICollections to other list/array types. Try:
public virtual ICollection<NamedChild> Children {get; set;}
Also, I'm a little confused about what you're trying to achieve with your custom constructors. It seems that all you're doing is initializing the properties on the instance. If that's the case, a custom constructor is not needed. Just use the class initialization syntax:
x => new NamedChild { ChildId = x.ChildId, Name = "" }

How do you use BsonClassMap to map a POCO domain object property as a manual or DBRef reference?

Using BsonClassMap, is it possible to map a domain object reference while keeping the domain object assembly persistent ignorant (changing the public A Reference { get; set; } property to public MongoDBRef Reference{ get; set; } in the sample class B below is not acceptable).
For this case, the referenced object is not a part of the same aggregate, and should not be stored as a nested document.
Is it possible map two domain objects in a relationship like this:
public class A
{
public Guid Id {get; private set; }
}
public class B
{
public Guid Id { get; private set; }
public A Reference { get; set; }
}
Into the following document structure:
// Collection for class A
{ _id: "11111111-1111-1111-1111-111111111111" }
// Collection class B
{
_id: "22222222-2222-2222-2222-222222222222",
reference_id: "11111111-1111-1111-1111-111111111111"
}
The mapping may look like:
BsonClassMap.RegisterClassMap<A>(cm =>
{
cm.MapIdProperty(c => c.Id)
.SetIdGenerator(new GuidGenerator())
.SetRepresentation(BsonType.String);
}
BsonClassMap.RegisterClassMap<B>(cm =>
{
cm.MapIdProperty(c => c.Id)
.SetIdGenerator(new GuidGenerator())
.SetRepresentation(BsonType.String);
// How do I map the B.Reference to a manual reference (like
// the sample doc structure above) or possibly as a DBRef?
}
So, without changing the model, how do I map the Reference property to object A, from object B as either a DBRef or as a manual references (as in my sample document structure above)?
Is this possible using BsonClassMap? Or in order to use BsonClassMap and keep my domain assembly persistent ignorant, do I need to change the model to something like:
public class A
{
public Guid Id {get; private set; }
}
public class B
{
public Guid Id { get; private set; }
public Guid ReferenceId { get; set; } // Don't reference the object directly,
// just store the Guid to the
// referenced object.
}
I posed this same question to the mongodb-csharp user group and got a response from craiggwilson:
You'll need to change your ReferenceProperty to ReferencePropertyId. We do not support lazy-loading (or eager-loading) of referenced documents.
Since A is not the aggregate for B, then this actually makes more sense when discussing in these terms. Generally, it is unnecessary for a referenced aggregate (B) to be loaded in order to process the referencing aggregate (A). It might be that you do indeed need some information from B. In this case, think about denormalizing a little and creating a true entity (BSummary) whose aggregate is A. This would make sense if some of the summary information is immutable or changes infrequently.

Pivoting an IEnumerable List

I am trying to apply a bit of groupby/crosstabbing logic to an IEnumerable list of a user defined object and was wondering if anyone could help me out. I'm stuck with an existing (rather annoying) object model to work with but anyway here goes...
consider the following class which I will condense to only relevant properties so you get the jist...
public class Holding
{
private void Institution;
private string Designation;
private Owner Owner;
private Event Event;
private Shares Shares;
}
I want to convert this into a list that satifys the following...
The object is grouped by Institution.
This parent list of institutions contains a list of a new object with a unique combination of Designation and Owner.
Now for each of this combination of Designation and Owner we get another child list of unique Events.
So it basically 3 lists deep.
I'm not sure if this is possible with an IEnumerable List or not, I have toyed around quite a bit with the GroupBy extension method to no avail thus far. I'd like most to do it this way, but I'm using linq-to-sql to get the initial list of holdings which is as follows and might be the better place to do the business...
public static List<Holding> GetHoldingsByEvents(
int eventId1,
int eventId2)
{
DataClassesDataContext db = new DataClassesDataContext();
var q = from h in db.Holdings
where
h.EventId == eventId1 ||
h.EventId == eventId2
select h;
return q.Distinct().ToList();
}
Any help/guidance would be much appreciated...
Thanks in advance.
I'm using ToLookup method, which is kind of a grouping, it takes two parameters, first one a function used for defining the group keys and the next one is a function used as a selector (what to take from the match).
items.ToLookup(c=>c.Institution.InstitutionId, c => new {c.Designation, c.Owner, c.Event})
.Select(c => new {
// find the institution using the original Holding list
Institution = items.First(i=>i.Institution.InstitutionId == c.Key).Institution,
// create a new property which will hold the groupings by Designation and Onwner
DesignationOwner =
// group (Designation, Owner, Event) of each Institution by Designation and Owner; Select Event as the grouping result
c.ToLookup(_do => new {_do.Designation, _do.Owner.OwnerId}, _do => _do.Event)
.Select(e => new {
// create a new Property Designation, from e.Key
Designation = e.Key.Designation,
// find the Owner from the upper group ( you can use items as well, just be carreful this is about object and will get the first match in list)
Owner = c.First(o => o.Owner.OwnerId == e.Key.OwnerId).Owner,
// select the grouped events // want Distinct? call Distinct
Events = e.Select(ev=>ev)//.Distinct()
})
})
I assumed your classes look like these
public class Holding
{
public Institution Institution {get; set;}
public string Designation {get; set;}
public Owner Owner {get; set;}
public Event Event {get; set;}
}
public class Owner
{
public int OwnerId {get; set;}
}
public class Event
{
public int EventId {get; set;}
}
public class Institution
{
public int InstitutionId {get; set;}
}

Categories