self reference entity model in wcf service - entity-framework

I created WCF service that returned a collection of product entities from an entity frame work model .that product has self-reference .I consume data from WCF service in silverlight application .
i use Asynchronous methods . product entity was modeled this form of:
Public partial class Product
{
Public Product(){
this.product_11=new HashSet<Product>;
}
[DataMember]
public int Id{get; set;}
[DataMember]
public Nullable<int> subPro{get; set;}
[DataMember]
Public virtual Icollection<Product> product_11{get; set;}
[DataMember]
Public virtual Product product_12{get; set;}
}
and i use that in service methode
productEntity ef=new productEntity();
[OperationContract]
Public IEnumerable<Product> Getproduct()
{
return ef.Product;
}
in run time whene call service methode i get Time out error
"the HTTP request has ... exceeded the allotted timeout"

I think the problem lies in the usage of IQueryable as the return type in combination with WCF services.
[OperationContract]
Public IEnumerable<Product> Getproduct()
{
return ef.Product.ToList();
}
In this case query is executed with the call of the ToList() method, thus the WCF has not to execute the IQueryable.
The second part is that you might run into serialization problems, when returning objects of the model from your context. Because EF injects the feature for lazy loading into your model classes by inheritance.
You should switch off lazy loading for your current context in the service method:
context.ContextOptions.LazyLoadingEnabled = false;
context.ContextOptions.ProxyCreationEnabled = false;
This is described in this link
The next thing is that the serializer, which translates the model classes into XML-message has troubles with circular references. Here is an example which could lead to a problem:
public class A
{
public string PropA { get; set; }
public virtual B PropB { get; set; }
}
public class B
{
public string PropC { get; set; }
public virtual A PropD { get; set; }
}
You can avoid this by using the CyclicReferencesAware attribute for the OperationContractmethod:
[OperationContract]
[CyclicReferencesAware(true)]
Public IEnumerable<Product> Getproduct()
{
return ef.Product.ToList();
}
Hope this helps you!

Related

Load a navigation property value using entity framework core without going through DB context

TL;DR: what's the most concise method to load a single navigation property on an entity?
Suppose I already have an instance entity Foo with a child Child. Instance of Foo I have has ChildId set but Child was not loaded, i.e. foo.ChildId == 1234 but foo.Child == null.
I want to get Child if it is missing. I know I can do:
if (foo.Child is null) {
foo.Child = _dbContext.Foos.Include(f => f.Child).Single(f => f.Id == foo.Id).Child;
}
but I am looking for a lazy way (pun!) to load it on-demand (I don't want to load all properties on-demand, however, just the one I want to load explicitly), something like:
var child = _dbContext.EnsureLoaded(da, e => e.Child);
Is there a way to do this?
Probably you are looking for Explicit Loading of Related Data
_dbContext.Entry(foo).Reference(f => f.Child).Load();
Lazy Loading is already available. There are two options:
using proxy objects generated by EF Core to automagically load related entities or
use the ILazyLoader service with POCOs to load related entities when requested
Proxies
To use proxies, the DbContext has to be configured first :
.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));
After that, any properties that need to be lazy loaded have to be made virtual :
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public virtual Blog Blog { get; set; }
}
At runtime EF will return proxy objects that inherit from the entity classes and overload the lazy properties to load the related object when first requested.
ILazyLoader service
Another option, that doesn't require inheritance, is to use POCOs and the ILazyLoader service to load the entities when needed :
public class Blog
{
private ICollection<Post> _posts;
public Blog()
{
}
private Blog(ILazyLoader lazyLoader)
{
LazyLoader = lazyLoader;
}
private ILazyLoader LazyLoader { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts
{
get => LazyLoader.Load(this, ref _posts);
set => _posts = value;
}
}
This adds a dependency on the ILazyLoader interface itself, which in turn adds a dependency to EF Core in domain or business models.
This can be avoided by injecting the loader as a lambda, along with some convention magic :
public class Blog
{
private ICollection<Post> _posts;
public Blog()
{
}
private Blog(Action<object, string> lazyLoader)
{
LazyLoader = lazyLoader;
}
private Action<object, string> LazyLoader { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts
{
get => LazyLoader.Load(this, ref _posts);
set => _posts = value;
}
}
This is used in combination with an extension method that actually calls the loader using the property's name and sets its backing field :
public static class PocoLoadingExtensions
{
public static TRelated Load<TRelated>(
this Action<object, string> loader,
object entity,
ref TRelated navigationField,
[CallerMemberName] string navigationName = null)
where TRelated : class
{
loader?.Invoke(entity, navigationName);
return navigationField;
}
}
As the docs warn:
The constructor parameter for the lazy-loading delegate must be called "lazyLoader". Configuration to use a different name than this is planned for a future release.

EF : Returning linked tables

Is this the correct way I can get linked tables using where or is there another way to return the data.
GetMethod
public IEnumerable<Model.MeetingPollingQuestion> GetMeetingPollingQuestion(int MeetingPollingId)
{
using (var db = new NccnEcommerceEntities())
{
using (DbContextTransaction dbTran = db.Database.BeginTransaction())
{
var ListOfMeetingPollingQuestions = (from mpq in db.MeetingPollingQuestions
where (mpq.MeetingPollingId == MeetingPollingId)
select new Model.MeetingPollingQuestion
{
MeetingPollingId = mpq.MeetingPollingId.Value,
MeetingPollingQuestionType = mpq.MeetingPollingQuestionType,
MeetingPollingParts = (from mp in db.MeetingPollingParts
where mp.MeetingPollingPartsId == mpq.MeetingPollingId
select new Model.MeetingPollingParts
{
Type= mp.Type
}).ToList(),
}).ToList();
return ListOfMeetingPollingQuestions;
}
}
}
EF Model
namespace Repository.EFModel
{
using System;
using System.Collections.Generic;
public partial class MeetingPolling
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MeetingPolling()
{
this.MeetingPollingQuestions = new HashSet<MeetingPollingQuestion>();
}
public int MeetingPollingId { get; set; }
public Nullable<int> MeetingId { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<System.DateTime> EndDate { get; set; }
public string PollingTitle { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MeetingPollingQuestion> MeetingPollingQuestions { get; set; }
}
}
namespace Repository.EFModel
{
using System;
using System.Collections.Generic;
public partial class MeetingPollingQuestion
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MeetingPollingQuestion()
{
this.MeetingPollingParts = new HashSet<MeetingPollingPart>();
}
public int MeetingPollingQuestionId { get; set; }
public string MeetingPollingQuestionType { get; set; }
public Nullable<int> MeetingPollingId { get; set; }
public Nullable<int> SequenceOrder { get; set; }
public virtual MeetingPolling MeetingPolling { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MeetingPollingPart> MeetingPollingParts { get; set; }
}
}
namespace Repository.EFModel
{
using System;
using System.Collections.Generic;
public partial class MeetingPollingPart
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MeetingPollingPart()
{
this.MeetingPollingPartsValues = new HashSet<MeetingPollingPartsValue>();
}
public int MeetingPollingPartsId { get; set; }
public string Type { get; set; }
public Nullable<int> MeetingPollingQuestionId { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MeetingPollingPartsValue> MeetingPollingPartsValues { get; set; }
public virtual MeetingPollingQuestion MeetingPollingQuestion { get; set; }
}
}
Your entities have navigation properties for the related entities, so if you want to return entities and their relatives, just eager load the related entities using Include.
public IEnumerable<Model.MeetingPollingQuestion> GetMeetingPollingQuestion(int MeetingPollingId)
{
using (var db = new NccnEcommerceEntities())
{
var questions = db.MeetingPollingQuestions
.AsNoTracking()
.Include(mpq => mpq.MeetingPollingType)
.Include(mpq => mpq.MeetingPollingParts)
.Where(mpq => mpq.MeetingPollingId == MeetingPollingId)
.ToList();
return questions;
}
}
... and that's it. The important details here is the use of Include to eager load related data, and the use of AsNoTracking to ensure that the loaded entities are not tracked by the DbContext. These will be detached entities, copies of the data but otherwise not tracking changes or an association with a DbContext. These are suitable for read-only access to the data they contain.
Whenever returning "entities" outside of the scope of a DbContext you should ensure that they are non-tracked or detached. This is to avoid errors that can come up with potential lazy load scenarios complaining about that an associated DbContext has been disposed, or errors about references being tracked by another DbContext if you try associating these entities to a new DbContext. Your code performing a Select with a new class instance does the same thing, just more code.
Personally I do not recommend working with detached entities such as ever returning entities outside of the scope of the DbContext that they were read from. Especially if you decide you only need a subset of data that the entity ultimately can provide. Entities reflect the data state, and should always be considered as Complete, or Complete-able. (i.e. Lazy loading enabled) If the code base has some code that works with tracked entities within the scope of a DbContext, vs. detached entities, vs. copies of entity classes that might be partially filled or deserialized, it makes for buggy, unreliable, and un-reusable code. Take a utility method that accepts a MeetingPollingQuestion as a parameter. As far as that method is concerned it should always get a complete MeetingPollingQuestion. The behaviour of this method could change depending on whether it was given a tracked vs. detached, vs. partially filled in copy of a MeetingPollingQuestion class. Methods like this would need to inspect the entity being passed in, and how reliable can that logic be for determining why a related entity/collection might be missing or #null?
If you need to pass entity data outside the scope of the DbContext where you cannot count on that data being complete or related data being lazy loaded as a last resort, then I recommend using POCO DTOs or ViewModels for those detached or partial representations of the data state. With a separate POCO (Populated by Select or Automapper) there is no confusion between that representation and a tracked Entity.

How to add EntitySet when using Breeze EdmBuilder

FINAL EDIT : I will put the answer here at the top for other people who are searching. The main problem was the namespace mismatch caused by db-first generated EDM attaching '.Models' to the end of the model namespace. This namespace did not matched with the odata namespace so the route was failing. I just edited out all the occurances of '.Models' from the namespace and now it's working.
A newbie trying out Breeze with webApiOdata set up. Sorry if this question is a trivial one.
I have a db generated edmx model with webapi odata controllers. I was having problem with getting the correct metadata to show until I read about the new Breeze EdmBuilder.
That solved the problem of getting the correct metadata to show but now, I can not route to any of the tables. If I try /odata/Customers I get a 406 error.
Before, I was using ODataConventionModelBuilder to set the EntitySets and that worked fine.
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Detail>("Details");
builder.EntitySet<Item>("Items");
builder.EntitySet<Order>("Orders");
builder.EntitySet<Customer>("Customers");
Now, since I am using EdmBuilder, how do I set the EntitySets so that I can route to proper data?
I hope the question makes sense.
* EDIT : I have added the listing of GCSodContext and a snippet from the Customers controller.
namespace GCSbz3.Models
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class GCSodContext : DbContext
{
public GCSodContext()
: base("name=GCSodContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<Detail> Details { get; set; }
public virtual DbSet<Item> Items { get; set; }
public virtual DbSet<Order> Orders { get; set; }
}
}
and Here is the Customers controller
...
using System.Web.Http;
using System.Web.Http.ModelBinding;
using System.Web.Http.OData;
using System.Web.Http.OData.Routing;
using GCSbz3.Models;
namespace GCSbz3.Controllers
{
public class CustomersController : ODataController
{
private GCSodContext db = new GCSodContext();
// GET odata/Customers
[Queryable]
public IQueryable<Customer> GetCustomers()
{
return db.Customers;
}
...
Here is the Customer class.
namespace GCSbz3.Models
{
using System;
using System.Collections.Generic;
public partial class Customer
{
public Customer()
{
this.Orders = new HashSet<Order>();
}
public int CustID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public string Phone { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
}
Check your ODataController name, it needs to be aligned with EntitySet name in your edmx.
If the set name is CustomerSet, controller needs to be CustomerSetController with a public GetCustomerSet method.
For instance this works;
TestDbContext.cs
public partial class TestDbContext : DbContext
{
public TestDbContext()
: base("name=TestDbContext")
{}
public virtual DbSet<A1> A1Set { get; set; }
}
A1SetController.cs
public class A1SetController : ODataController
{
private TestDbContext db = new TestDbContext();
// GET odata/A1Set
[Queryable]
public IQueryable<A1> GetA1Set()
{
return db.A1Set;
}
}
And routing setup in WebApiConfig.cs
// OData routes
config.Routes.MapODataRoute(
routeName: "odata",
routePrefix: "odata",
model: EdmBuilder.GetEdm<TestDbContext>(),
batchHandler: new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
And last, edmx and actual model (class) namespaces need to be aligned. When you make a request to $metadata, you see the defined namespace for your model. You can change it in your Model Designer, right click to an empty area, click to Properties. In Properties window, you can see Namespace attribute. In my case;
<Schema Namespace="Web">
<EntityType Name="Customer">
And Customer.cs
namespace Web
{
using System;
using System.Collections.Generic;
public partial class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
}

Unable to insert new records using Entity Framework 6 + Code First + Castle Windsor

I know this may be a simple question, but I'm pretty new to architecture and I want to do it right. So, thank you for your comprehension.
I'm also new to Castle Windsor and not used with Unit Of Work neither Repository patterns - And I even don't know if I need them to solve the problem I'm having at the moment.
What I'm trying to accomplish:
I have an interface called IDomain with just some properties and a concrete POCO class Domain that implements it.
IDomain interface:
public interface IDomain : IPersistentObject
{
int DomainId { get; set; }
string Name { get; set; }
[LocalizedString]
string ItemName { get; set; }
[LocalizedString]
string ItemDescription { get; set; }
int ItemValue { get; set; }
}
Domain POCO Class:
public class Domain : AbstractDefault, IDomain, ILocalizedEntity
{
public virtual int DomainId { get; set; }
public virtual string Name { get; set; }
[LocalizedString]
public virtual string ItemName { get; set; }
[LocalizedString]
public virtual string ItemDescription { get; set; }
public virtual int ItemValue { get; set; }
}
My DomainService.cs class does this:
public void Insert(IDomain param)
{
using (var db = new DefaultContext())
{
new DomainValidation(new DbMetaData().GetMetaData, Settings.Default.CultureName).Validate(param);
db.Domains.Add((Domain)param);
}
}
Another important info is that I'm using AOC, i.e., I'm intercepting method calls to my Domain class. See my Windsor container Installer:
public class Installers : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component
.For<IInterceptor>()
.ImplementedBy<Class1>()
.Named("DomainInterceptor"))
.Register(Component
.For<IDomain>()
.ImplementedBy<Domain>()
.LifestyleTransient()
.Interceptors(InterceptorReference.ForKey("DomainInterceptor")).Anywhere);
}
}
In my Unit Test I am doing:
var domain = container.Resolve<IDomain>(); // Returns IDomainProxy, not IDomain
domain.Name = "MIN_MAX";
domain.ItemName = new LocalizedProperty("en-US", "Mininum").Serialize();
domain.ItemValue = (int)MinMax.Minimum;
new DomainService().Insert(domain); // If I try to cast by doing .Insert(domain as Domain), I get a null
But when my code reaches the ".Add(Domain)param)" (DomainService.cs) I get the error: "Unable to cast object of type 'Castle.Proxies.IDomainProxy' to type 'Model.Domain'."
Why am I getting this error and how am I supposed to fix it, considering that I do want to use IoC, Windsor, etc?
Best regards.
In those situations Castle Windsor creates new instances with a "proxy" interface. I ended up using AutoMapper in my Service class.

Entity Framework Prevent Direct POCO Creation

I am facing a scenario in which I need to prevent direct creation of entity objects.
I am using Code First. I would like to have a method somewhere only using which I should be able to create the object. Is there any commonly used practice for this?
EF can work with entities having private/protected constructors.
So lets take this sample context:
public class MyEntity
{
protected MyEntity() { }
public int Id { get; set; }
public string Name { get; set; }
}
public class MyContext : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
}
Then creating an entity with new MyEntity() will result in compilation error.
But you can still create entites through EF with DbSet.Create myContext.MyEntities.Create(); and all other operations on MyEntity will work e.g. queries and updates etc as expected.
And of course you can also have a static factory method on MyEntity which manages the object creation
public class MyEntity
{
//...
public static MyEntity MyCreate()
{
return new MyEntity();
}
}