Loading Parent Child data using Entity Framework stored procedure - c#

I have two stored procedures, one to load parent data and other to load child data. Is there anyway to do this in a better way? Please see code below.
public partial class Product
{
public long Id { get; set; }
public string ProductId { get; set; }
public string Name { get; set; }
public string ProductionNo { get; set; }
public string UniqueIdentificationNo { get; set; }
public virtual ICollection<Process> Processes { get; set; }
}
public List<GetProductsBetween_Result> GetProductsBetween(DateTime? startDate, DateTime? endDate)
{
var products = DbContext.GetProductsBetween(startDate, endDate).ToList();
foreach(var product in products)
{
product.Processes = DbContext.GetWaitingTime(product.Id).ToList();
}
return products;
}

This entire scenario can be rewritten using Linq(Language Intergrated Query).
You can apply eager loading to fetch the Processes of a product. This is similar
to sql joins which Linq provides, such a state that code is optimised and foreachs
and hits to the server can be reduced
var products = from u in dbContext.Product.Include(u => u.Processes)
select new ProductView
{
item1 = XXX,
item2 = yyy
};
var newdata = user.ToList().where("some lambda expressions")
with conditions to filter date

I had the same issue with a really complex search that had to return the full tree of an object.
What you need to do is:
Make a stored procedure that returns in only one call multiple result sets for the root object and for all its dependent objects:
i.e. (add your own conditions)
SELECT p.* FROM Products p WHERE p.Name LIKE '%test%';
SELECT DISTINCT r.* FROM Processes r INNER JOIN Products p ON p.id = r.idProduct WHERE p.Name LIKE '%test%';
After the return, re-attach the parent objects with its childs as described in this article:
https://blogs.infosupport.com/ado-net-entity-framework-advanced-scenarios-working-with-stored-procedures-that-return-multiple-resultsets/
You will need to iterate each Product from the first result set and attach its Processes.
This should be much faster since you only make one round-trip to the database and less queries.

Related

C# GroupBy Trouble

As of now, I am trying to create a list that groups based on certain criteria and then display that list in the view.
I have two database tables and one is an association table.
First Table
public partial class InitialTraining
{
public InitialTraining()
{
InitialTrainingAssociations = new HashSet<InitialTrainingAssociation>();
}
public int Id { get; set; }
[ForeignKey("MedicInfo")]
public int TfoId { get; set; }
[ForeignKey("InstructorInfo")]
public int? InstructorId { get; set; }
[ForeignKey("PilotInfo")]
public int? PilotId { get; set; }
public DateTime DateTakenInitial { get; set; }
public decimal FlightTime { get; set; }
public bool Active { get; set; }
[StringLength(2000)]
public string Narrative { get; set; }
[Required]
[StringLength(20)]
public string TrainingType { get; set; }
[ForeignKey("CodePhase")]
public int PhaseId { get; set; }
[ForeignKey("PhaseTrainingType")]
public int PhaseTrainingTypeId { get; set; }
public string EnteredBy { get; set; }
public DateTime? EnteredDate { get; set; }
public virtual MedicInfo MedicInfo { get; set; }
public virtual MedicInfo InstructorInfo { get; set; }
public virtual MedicInfo PilotInfo { get; set; }
public virtual Code_Phase CodePhase { get; set; }
public virtual Code_PhaseTrainingType PhaseTrainingType { get; set; }
public virtual ICollection<InitialTrainingAssociation> InitialTrainingAssociations { get; set; }
}
Second Table (Association Table)
public class InitialTrainingAssociation
{
public int Id { get; set; }
[ForeignKey("InitialTraining")]
public int InitialTrainingId { get; set; }
[ForeignKey("CodePerformanceAnchor")]
public int? PerformanceAnchorId { get; set; }
[ForeignKey("GradingSystem")]
public int? GradingSystemId { get; set; }
public virtual AviationMedicTraining.CodePerformanceAnchor CodePerformanceAnchor { get; set; }
public virtual InitialTraining InitialTraining { get; set; }
public virtual GradingSystem GradingSystem { get; set; }
}
Here is my GroupBy in C#.
// get list of initial training record ids for statistics
var lstInitialTrainings = db.InitialTrainings.Where(x => x.TfoId == medicId && x.Active).Select(x => x.Id).ToList();
// get list of initial training performance anchors associated with initial training records
var lstPerformanceAnchors = db.InitialTrainingAssociations
.Where(x => lstInitialTrainings.Contains(x.InitialTrainingId)).GroupBy(t => t.PerformanceAnchorId)
.Select(s => new MedicStatistic()
{
PerformanceAnchorName = db.CodePerformanceAnchor.FirstOrDefault(v => v.Id == s.Key).PerformanceAnchor,
AnchorCount = s.Count()
}).ToList();
My Goal
Obviously from my code I want to group by the performance anchor in the association table, but I need more information from the Initial Training table to include in my ViewModel MedicStatistic, but I am having trouble figuring out the best way to do it.
My overall goal is to be able to get the most recent time a performance anchor was completed from the Initial Training table.
Visual
Initial Training Table (not all fields were captured in snippet b/c they're not important for the purpose of this question)
Initial Training Association Table
What I expect
So, from the pictures provided above as you can see there are multiple 1's for performance anchor id's in the association table, but they each have different InitialTrainingId. So, this specific performance anchor has been done multiple times, but I need to get the most recent date from the Initial Training table. Also, I need to get the corresponding grade with the anchor from the Grading System table, based on the most recent date.
So, for the performance anchor that equals 1.. I would want the grade that corresponds to the InitialTrainingId of 17 because that record was the most recent time that the performance anchor of 1 was done.
If you have any questions please let me know.
You want the data grouped by CodePerformanceAnchor, so the most natural way to start the query is at its DbSet which immediately eliminates the necessity of grouping:
from pa in db.CodePerformanceAnchors
let mostRecentInitialTraining
= pa.InitialTrainingAssociations
.Select(ita => ita.InitialTraining)
.OrderByDescending(tr => tr.DateTakenInitial)
.FirstOrDefault()
select new
{
pa.PerformanceAnchor,
mostRecentInitialTraining.DateTakenInitial,
mostRecentInitialTraining. ...
...
AnchorCount = pa.InitialTrainingAssociations.Count()
}
As you see, only navigation properties are used and the query as a whole is pretty straightforward. I assume that the PerformanceAchor class also has an InitialTrainingAssociations collection.
I can't guarantee that EF will be able to execute it entirely server-side though, that's always tricky with more complex LINQ queries.
I'm going to ignore the virtual properties in your InitialTrainingAssociation class, since you didn't mention anything about them and it's not immediately apparent to me whether they actually contain data, or why they are virtual.
It seems like IQueryable.Join is the easiest way to combine the data you want.
In the following example, we will start with the entries from the InitialTrainings table. We will then Join with the InitialTrainingAssociations table, which will result in a collection of paired InitialTraining and InitialTrainingAssociation objects.
var initialTrainingResults =
// Start with the InitialTrainings data.
db.InitialTrainings
// Add association information.
.Join(
// The table we want to join with
db.InitialTrainingAssociations,
// Key selector for the outer type (the type of the collection
// initiating the join, in this case InitialTraining)
it => it.Id,
// Key selector for the inner type (the type of the collection
// being joined with, in this case InitialTrainingAssociation)
ita => ita.InitialTrainingId,
// Result selector. This defines how we store the joined data.
// We store the results in an anonymous type, so that we can
// use the intermediate data without having to declare a new class.
(InitialTraining, InitialTrainingAssociation) =>
new { InitialTraining, InitialTrainingAssociation }
)
From here, we can add data from the PerformanceAnchors and GradingSystems tables, by performing more Joins. Each time we perform a Join, we will add a new entity to our anonymous type. The result will be a collection of anonymous types representing data we retrieved from the database.
// Add performance anchor information.
.Join(
db.PerformanceAnchors,
x => x.InitialTrainingAssociation.PerformanceAnchorId,
pa => pa.Id,
(x, PerformanceAnchor) =>
new { x.InitialTrainingAssociation, x.InitialTraining, PerformanceAnchor }
)
// Add grading system information.
.Join(
db.GradingSystems,
x => x.InitialTrainingAssociation.GradingSystemId,
gs => gs.Id,
// No need for InitialTrainingAssociation anymore, so we don't
// include it in this final selector.
(x, GradingSystem) =>
new { x.InitialTraining, x.PerformanceAnchor, GradingSystem }
);
(This was a verbose example to show how you can join all the tables together. You can use less Joins if you don't need to access all the data at once, and you can filter down the InitialTrainings collection that we start with if you know you only need to access certain pieces of data.)
At this point, initialTrainingResults is an IEnumerable containing one entry for each association between the InitialTrainings, PerformanceAnchors, and GradingSystems tables. Essentially, what we've done is taken all the InitialTrainingAssociations and expanded their Ids into actual objects.
To get the most recent set of data for each performance anchor:
var performanceAnchors = initialTrainingResults
// Group by each unique Performance Anchor. Remember, the IEnumerable
// we are operating on contains our anonymous type of combined Training,
// Performance Anchor and Grading data.
.GroupBy(x => x.PerformanceAnchor.Id)
// Order each Performance Anchor group by the dates of its training,
// and take the first one from each group
.Select(g => g.OrderByDescending(x => x.InitialTraining.DateTakenInitial).First());
In the Select you can order the group result to get the most recent associated InitialTraining by DateTakenInitial, and from there get the desired data
//...omitted for brevity
.GroupBy(t => t.PerformanceAnchorId)
.Select(g => {
var mostRecent = g.OrderByDescending(_ => _.InitialTraining.DateTakenInitial).First();
// get the corresponding grade with the anchor from the Grading System table
var gradeid = mostRecent.GradingSystemId;
var gradingSystem = mostRecent.GradingSystem;
//get the most recent date from the Initial Training
var mostRecentDate = mostRecent.InitialTraining.DateTakenInitial
//..get the desired values and assign to view model
var model = new MedicStatistic {
//Already have access to CodePerformanceAnchor
PerformanceAnchorName = mostRecent.CodePerformanceAnchor.PerformanceAnchor
AnchorCount = g.Count(),
MostRecentlyCompleted = mostRecentDate,
};
return model;
});

Accessing virtual child object executes sql without WHERE clause

I have tried to research why, what I believe should be a relatively straightforward concept, is not working as expected. From what I have read the following should work in the way I expect, but it isn't.
I am retrieving data from an SQL database using entity framework, however I cannot get Lazy / Deferred loading to work when accessing child objects.
Here is my class
public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string ShortDescription { get; set; }
public string FullDescription { get; set; }
public virtual IList<ProductEvent> Events { get; set; } = new List<ProductEvent>();
}
I then assign a variable to a Product
var product = ServiceController.ProductService.GetProduct(123456);
and the GetProduct method:
public Product GetProduct(int id, params Expression<Func<Product, object>>[] includedProperties)
{
IQueryable<Product> products = _db.Products;
if (includedProperties != null)
{
foreach (var includeProperty in includedProperties)
{
products = products.Include(includeProperty);
}
}
return products.Single(p => p.Id == id);
}
The generated SQL includes a WHERE clause when I call the method and pass in a Product ID, as expected. So far, so good.
My problem arises when I try to access a sub-set of Events which are related to this Product:
var desiredEvent = product.Events.SingleOrDefault(e => e.StartDateTime == '2017-07-01T02:00');
I would expect the generated SQL to contain a WHERE clause to only return Events with a matching StartDateTime, however the SQL does not contain any WHERE clause so all Product Events are loaded into memory and filtered there. Some of my Products have over 100,000 events so this is causing performance issues.
I cannot understand what is wrong with the code which is causing my filter to be ignored when Events are accessed.
Am I missing something fundamental here with the way EF handles queries? Or is the way I am accessing the Product in the first place causing the problem?

ASP.NET MVC LINQ Entity Framework recursive

I'm not sure how to write LINQ query. I have these models:
class Category
{
ICollection<Thread> Threads {get;set;}
ICollection<Category> SubCategories {get;set;}
}
class Thread
{
Category Category {get;set;}
//Some Stuff
}
So, there could be categories linked like -
Category1
Category2
Category3
Category4
Category5
Category6
I want find all threads linked to Category2 and it SubCategories(3, 4, 5).
I thought about just take Category1 form db, and using C# recursive function build List of threads i need, but i feel it's bad idea.
Any ideas or links would be great. Thank you!
There code, but there is Topics(in Threads), i didnt mention it couse it's not rly matter(at least i think so)
public ActionResult ShowCategoryTopics(int id)
{
var category = db.Categories.Where(x => x.Id == id).FirstOrDefault();
var topics = GetTopics(category);
return View();
}
public List<Topic> GetTopics(Category category)
{
List<Topic> topics = new List<Topic>();
if (!category.IsDeleted && !category.IsHidden)
return null;
foreach (Thread thread in category.Threads)
{
topics.AddRange(thread.Topics.Where(x => !x.IsDeleted).ToList());
}
foreach(Category childCategory in category.SubCategories)
{
topics.AddRange(GetTopics(childCategory));
}
return topics;
}
While EF can load joined records lazily and transparently, it can't load recursive joined records cause it's too complicate.
So, first of all, remove the Category.Threads navigation property:
public class Category
{
public int Id { get; set; }
public int? ParentId { get; set; }
// you can remove the attribute
[ForeignKey(nameof(ParentId))]
public virtual Category Parent { get; set; }
public string Title { get; set; }
public virtual ICollection<Category> SubCategories { get; set; } = new HashSet<Category>();
}
public class Thread
{
public int Id { get; set; }
public int CategoryId { get; set; }
// you can remove the attribute
[ForeignKey(nameof(Category))]
public Category Category { get; set; }
public string Title { get; set; }
}
Now you can use Common Table Expressions to recursive query and Database.SqlQuery<TElement> method to load the result of the query.
This is the SQL query to get all Threads corresponded to the specified #CategoryId and all its subcategories:
WITH RecursiveCategories(Id, ParentId, Title)
AS
(
SELECT Id, ParentId
FROM dbo.Categories AS c1
WHERE Id = #CategoryId
UNION ALL
SELECT Id, ParentId
FROM dbo.Categories AS c2
INNER JOIN c1 ON c2.ParentId = c1.Id
)
SELECT th.*
FROM dbo.Threads AS th
WHERE th.CategoryId IN (SELECT Id FROM RecursiveCategories)
The method to load threads of specified category recursively:
public IEnumerable<Thread> GetAllRecursivelyByCategoryId(int categoryId)
{
var query = #"WITH RecursiveCategories(Id, ParentId, Title)
AS
(
SELECT Id, ParentId
FROM dbo.Categories AS c1
WHERE Id = #CategoryId
UNION ALL
SELECT Id, ParentId
FROM dbo.Categories AS c2
INNER JOIN c1 ON c2.ParentId = c1.Id
)
SELECT th.*
FROM dbo.Threads AS th
WHERE th.CategoryId IN (SELECT Id FROM RecursiveCategories)";
var parameter = new SqlParameter("CategoryId", categoryId);
return _dbContext.Database
.SqlQuery<Thread>(query, parameter)
.AsEnumerable();
}
This method runs the recursive query and maps the result to enumerable of threads. Here is only one request to the SQL server, and the response contains only necessary threads.
The way to do this all in database would be to use a recursive Common Table Expression (CTE) to extract all the category hierarchy. However this is a bit difficult to implement using Linq without resorting to direct SQL.
As you state there will only be about 100 or so categories it may me simpler to do the category extraction in the code rather than database.
I'm assuming you have the foreign key columns as wells as the navigation properties.
First a Helper function, converts a list of categories to an enumerable of nested ids;
static IEnumerable<int> GetCategoryIds(IList<Category> categories, int? targetId) {
if (!targetId.HasValue) {
yield break;
}
yield return targetId;
foreach (var id in categories.Where(x => x.ParentId==targetId).SelectMany(x => GetCategoryIds(x.Id))) {
yield return id;
}
}
Now your query
var ids = GetCategoryIds(db.Categories.ToList(), 2).ToList();
var threads = db.Threads.Where(x => ids.Contains(x.CategoryId));

How to save multiple linq queries from a loop in a single variable?

I thought its possible to save multiple linq queries from a loop in a single variable ?
public ActionResult Index()
{
string ActiveUserId = (string)Session["ActiveUserGuid"];
Guid MyGuid = new Guid(ActiveUserId);
var queryRoots = from r in db.Roots
where r.UserId == MyGuid
select r.TaskId;
//Here is the questionable Part
foreach (var i in queryRoots)
{
var queryAllTasks = from t in db.Tasks
join b in db.Trees on t.TaskId equals b.ChildId
where b.TaskId == i
select t;
tasksForView.Add(queryAllTasks); <---????? obviously doesnt work
};
return View(queryAllTasks);
}
public class Root
{
public int RootId { get; set; }
public Guid UserId { get; set; }
public User User { get; set; } //navigation Property
public int TaskId { get; set; } // composite key
public int ChildId { get; set; }
public Tree Tree { get; set; } //navigation Property
}
public class Tree
{
public int TaskId { get; set; }
public int ChildId { get; set; }
public int Length { get; set; } //Path length
public virtual ICollection<Root> Roots { get; set; }
}
In case you are wondering what its supposed to do. I want to query several subtrees from a hierarchical transitiv closure table and return them to a view.
I know my code is not close to working and I just tried very simple solutions!
I guess a different way to do the query would get rid of the problem all together
Use Contains on your integer list:
var tasks =
from t in db.Tasks
join b in db.Trees on t.TaskId equals b.ChildId
where queryRoots.Contains(b.TaskId)
select t;
return View(tasks);
or do it all in one query:
var tasks =
from t in db.Tasks
join b in db.Trees on t.TaskId equals b.ChildId
join r in db.Roots on r.TaskId equals b.TaskId
where r.UserId == MyGuid
select t;
return View(tasks);
The problem here is that you're closing over the loop variable. LINQ queries use deferred execution whenever possible, so you're just defining what the query is and storing that, not calculating the results and storing them.
You have a few choices here. You could just add a ToList to the end of the query; it would eagerly evaluate it, and storing that list won't lead to problems.
What's likely breaking is that your query is using i, which is changed in the loop. Since the query doesn't actually evaluate what i is until after the end of the loop, i will always have whatever the last value was. This is easily fixed by just adding a new local variable inside of the loop and assigning i to it. Use that local variable in your query.
As others have said, queryAllTasks has deferred execution in each iteration of the loop. So all you're storing is an IQueryable.
What you want is
tasksForView.Add(queryAllTasks.ToList());
Also, I noticed you're trying to return queryAllTasks as your view model, but that variable is scoped to the for loop. I assume you want to return tasksForView as your model (which I further assume is declared elsewhere, as I don't see a declaration for it in the code you provided.)

Linq-to-SQL Load 1:1 Relations in a single query

We have several classes with multiple 1:1 Relationships for quick joins, and while this works fine for anonymous types for tabular display, I'm unsure how to fully populate the type in a single linq query.
We have these properties either because it's an off 1:1, or we don't want to query through a child collection to find a "primary" every display, we instead incur the cost by setting these Primary IDs on save.
A stripped down example for the context of this post:
public class Contact
{
public long Id { get; set; }
public EntitySet<Address> Addresses { get; set; }
public EntityRef<Address> PrimaryAddress { get; set; }
public long? PrimaryAddressId { get; set; }
public EntitySet<Email> Emails { get; set; }
public EntityRef<Email> PrimaryEmail { get; set; }
public long? PrimaryEmailId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Address
{
public long Id { get; set; }
public EntitySet<Contact> Contacts { get; set; }
public bool IsPrimary { get; set; }
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
public class Email
{
public long Id { get; set; }
public EntitySet<Contact> Contacts { get; set; }
public bool IsPrimary { get; set; }
public string Address { get; set; }
}
The problem is when displaying a list of contacts, the PrimaryAddress and PrimaryEmail have to be lazy loaded. If we do DataLoadOptions it doesn't give the desired effect either since it's a 1:1, example:
var DB = new DataContext();
var dlo = new DataLoadOptions();
dlo.LoadWith<Contact>(c => c.PrimaryAddress);
dlo.LoadWith<Contact>(c => c.PrimaryEmail);
DB.LoadOptions = dlo;
var result = from c in DB.Contacts select c;
result.ToList();
The above code results in a INNER JOIN since it treats it like a parent relationship, it doesn't respect the nullable FK relationship and left join the 1:1 properties. The desired query would be something like:
Select t1.*, t.2*, t3.*
From Contact t1
Left Join Address t2 On t1.PrimayAddressId = t2.Id
Left Join Email On t1.PrimaryEmailId = t3.Id
Is there a way to do this and get a IQueryable with these nullable 1:1 properties populated, or even a List? Due to other constraints, we need the type to be Contact, so anonymous types won't work. Pretty open to options, anything would be better than lazy loading n*(number of 1:1s)+1 queries for the number of rows we display.
Update: Finally got around to updating this, the devart guys have fixed the behavior in later versions to work perfectly. There's no need for DataLoadOptions at all, just using fields off the table works, for example:
var DB = new DataContext();
var result = from c in DB.Contacts
select new {
c.Id
c.FirstName,
c.LastName,
Address = c.PrimaryAddress.Street1 + " " + c.PrimaryAddress.Street2 //...
Email = c.PrimaryEmail.Address
};
This correctly performs a single left outer join to the related Address and Email tables. Now the fix is specific to the situation here of getting this anonymous type...but they also fixed the DataLoadOptions behavior where we do need it, correctly keyed off the foreign key type now. Hope this update helps others on an older version...I highly recommend upgrading, there are lots of new enhancements in versions since 5.35 (many making life much easier).
Original:
What we ended up with was a different approach. This may be specific behavior to the devart: dotConnect for Oracle provider (as of version 5.35.62, if this behavior changes I'll try and update this question).
var DB = new DataContext();
var result = from c in DB.Contacts
select new {
c.Id
c.FirstName,
c.LastName,
Address = new AddressLite {
Street1 = c.PrimaryAddress.Street1,
Street2 = c.PrimaryAddress.Street2,
City = c.PrimaryAddress.City,
State = go.PrimaryAddress.State,
Country = go.PrimaryAddress.Country },
Email = c.PrimaryEmail.Address
};
result.ToList();
This results in a single query. While calling a child object in the select, e.g. c.PrimaryAddress does not cause a join to occur (resulting in a lot of select ... from address where id = n lazy loads, one per row of tabular data we're displaying), calling a property on it however, e.g. c.PrimaryAddress.Street1 DOES cause a correct left join in the address table in the query query. The linq above works only in linq-to-sql, it would fail with null reference on linq-to-entities, but...in the case we're dealing with that's fine.
The good:
Single query, producing left joins to Address and Email
Lightweight objects for address and down to just a string for email (they both have some back-reference EntiySet in the real project, making them more expensive than necessary for simple tabular display needs)
Fast/clean, the above is a much simpler query than manually joining every child table we were doing, cleaner code.
Performance, the creation of the heavier objects was quite a hit, changing from Email to string, Address to AddressLite and (in the full project) Phone to PhoneLite resulted in pages just displaying tabular data going from 300-500ms down to 50-100ms.
The Bad:
Anonymous type, there are cases where we need a strong type, having to create those (even as quick as ReSharper makes this task) adds a lot of clutter.
Since we can't modify and save an anonymous type, or any type we create without a good deal of annotation work, which must be updated if the model changes anything around that. (since those classes aren't generated)
Left join is generated if IsForeignKey is set to false in the association attribute for the EntityRef-typed property.
We came up against much the same problem with the DataLoadOptions, lazy loading and your primary records.
To be honest I'm not totally happy with the solution we came up with as it's not exactly very neat, and the SQL query it produces can be complicated, but essentially we created wrapper classes with copies of the fields we wanted to force load and used sub queries to load in the records. For your example above:
public class ContactWithPrimary
{
public Contact Contact { get; set; }
public Email PrimaryEmail { get; set; }
public Address PrimaryAddress { get; set; }
}
Then an example LINQ query would be:
List<ContactWithPrimary> Contacts = DataContext.Contacts
.Select(con => new ContactWithPrimary
{
Contact = con,
PrimaryEmail = con.PrimaryEmail,
PrimaryAddress = con.PrimaryAddress
}).ToList();
What it does do however is pull it out in a single query.
You might want to take a look at Rob Conery's Lazy List implementation.
http://blog.wekeroad.com/blog/lazy-loading-with-the-lazylist/
It basically hides the entire lazy loading implementation from you and you don't need to specify any loading options.
The only drawback is that it only works for lists. It is however possible to write an implementation for properties as well. Here is my effort.
public class LazyProperty<TEntityType> where TEntityType : class
{
private readonly IQueryable<TEntityType> source;
private bool loaded;
private TEntityType entity;
public LazyProperty()
{
loaded = true;
}
public LazyProperty(IQueryable<TEntityType> source)
{
this.source = source;
}
public TEntityType Entity
{
get
{
if (!loaded)
{
entity = source.SingleOrDefault();
loaded = true;
}
return entity;
}
set
{
entity = value;
loaded = true;
}
}
}

Categories

Resources