EF Code First, create new object in collection with a proxy - entity-framework-4.1

How can I create+persist+have-a-proxy-to a new instance of a code-first poco using only navigation property collections? In the bellow code, I show how you might want to do this, if using member functions to create POCOs that then create POCOs. You don't have a DbContext, but if you create an object and persist it using DbSet.Add, the returned object isn't a proxy, so you can't in turn use its DbSet.Add to add a different sub-object.
In this code, if you call MailingList.AddIncomingMessage("my message"), you get an exception at the "OOPS" comment, because the created msg isn't a proxy and thus its Message.doodads property is null.
class Doodad {
public int ID { get; set; }
public string doodad { get; set; };
}
class Message {
public int ID { get; set; }
public virtual MailingList mailingList { get; set; }
public virtual ICollection<Doodad> doodads { get; set; }
public string text { get; set; }
public void GetDoodadCreateIfNeeded(string doodad) {
try {
// won't be found since we just created this Message
return this.doodads.First(d => d.doodad == doodad);
} catch (Exception e) {
Doodad newDoodad = new Doodad() { doodad=doodad };
// OOPS! this.doodads == null, because its not a proxy object
this.doodads.Add(newDoodad);
return newDoodad;
}
}
}
class MailingList {
public int ID { get; set; }
public virtual ICollection<Message> messages { get; set; }
public void AddIncomingMessage(string message) {
var msg = new Message() { text=message };
// we have no Context, because we're in a POCO's member function
this.messages.Add(msg);
var doodad = msg.GetDoodadCreateIfNeeded("bongo drums");
}
}
EDIT: sorry guys, I forgot to put the property accessors and ID in for this simplified case, but I am using them in the actual code.

It has nothing to do with proxies. It is the same as any other code - if you want to use object / collection you must first initialize it! Your fist command:
return this.doodads.First(d => d.doodad == doodad);
doesn't throw exception because it didn't find doodad but because the doodads is null.
What do you need to do? You need to initialize collections before you first use them. You can do it:
Directly in their definition
In entity's constructor
In property getter (lazy initialization) once they are first needed - that would require to change your fields to properties which is btw. correct way to write classes in .NET
In your custom methods you can check if they are null and initialize them

Complementary to the navigation property, you need to have a property that is the Id of the foreign key.
So your MailingList will need to have this property:
[Key] // this attribute is important
public int Id { get; set; }
and you'll have to change the Message classe to have these properties:
public virtual int mailingListId { get; set;
public virtual MailingList mailingList { get; set; }
The { get; set; } property is important, so that it is a property, not just a public attribute.

Related

Model State Always true even when the required field is not sent

I am simply calling an API and passing an object as a parameter and everything works fine. But then i wanted to validate the model before going any further so i simply wrote [Required] above the fields i always wanted filled.
MODEL
public class Consent
{
public Consent()
{
}
public int Id { get; set; }
[Required]
public int FacilityId { get; set; }
public string Heading { get; set; }
public string Description { get; set; }
}
and validate the model state in controller like this
public ActionResult<int> AddConsent(Consent consent)
{
if(!ModelState.IsValid){
throw new CustomException("000-0000-000", "Validation failed");
}
//Further Code
}
By this i expected model state to be false when i don't send the facilityId when i call the api
JSON
{
"heading": "HeadingFromPostman5",
"description": "DiscriptiomFromPostman5"
}
but its still true . I know .Net core is allocating 0 to int value when null but how can i validate it then? Whats the work around for this?
Simply replace this line:
[Required]
public int FacilityId { get; set; }
With this:
[Required]
public int? FacilityId { get; set; }
The Required attribute works well for nullable reference objects. For primitives, when an instance is created, the default value (in this case 0 for int) is assigned for FacilityId, and hence the Required won't work. If you make the FacilityId as nullable int then the Required attribute will work fine.
[Required]
public int? FacilityId { get; set; }

Return self referencing model in JSON format using Web Api 2 controller

I have a self referencing model called Folder and also an Entity called Content which contains the Folder Entity.
public class Folder : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public virtual Folder Parent { get; set; }
public virtual ICollection<Folder> Children { get; set; }
}
public class Content : BaseEntity
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string HTML { get; set; }
public string Summary { get; set; }
public int XmlConfigId { get; set; }
public int FolderId { get; set; }
public virtual Folder Folder { get; set; }
}
Here is my Application Db context
public class ApplicationDbContext: DbContext
{
public DbSet<Folder> Folders { get; set; }
public DbSet<Content> Contents { get; set; }
public ApplicationDbContext() : base("ProjectDB") {
Database.SetInitializer<ApplicationDbContext>(null);
}
}
Everything works fine if i am using a razor view to display the data and also i am able to access the The Folder property that is inside the Content Entity.
The problem is when i try to display the data using Web API.
My web API
public class ContentApiController : ApiController
{
[HttpGet]
public IEnumerable<Content> GetAllContents()
{
return _unitofwork.Contents.GetAllContents();
}
}
On the Web API, the GetAllContents() function just returns the Entity models coming directly from the Folders DBSet. It is not calling the ToList() function since i want to do lazy loading. Here is the code for the GetAllContents() function.
public IEnumerable<Content> GetAllContents()
{
return ApplicationDbContext.Contents.Include(c=>c.Folder);
}
So in order for this to work i have to add.
Configuration.LazyLoadingEnabled = false;
to my applicationDbContext constructor which i really don't want.
and also
Global.asax
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
WebApiConfig
JsonMediaTypeFormatter jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().Single();
jsonFormatter.UseDataContractJsonSerializer = false;
jsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
jsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
jsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
Is there any way to expose the json data without out turning off Lazy loading. Thanks.
Just call ToList on your query, or, even better, ToListAsync:
[HttpGet]
public async Task<IEnumerable<Content>> GetAllContents()
{
return await _unitofwork.Contents.GetAllContents().ToListAsync;
}
Even if you enable LazyLoading, you cannot avoid to materialize your data before returning it to the client (and let the Serializer do its work).
In your MVC example, the framework itself enumerates the result in your View (I suppose), and thus you are not directly calling ToList, but in your scenario you have to materialize your Entities explicitly.
Please note that there is no performance issue in calling ToList/ToListAsync in your controller.

How to omit Get only properties in servicestack json serializer?

I have an object which I am de-serializing using ToJson<>() method from ServiceStack.Text namespace.
How to omit all the GET only propeties during serialization? Is there any attribute like [Ignore] or something that I can decorate my properties with, so that they can be omitted?
Thanks
ServiceStack's Text serializers follows .NET's DataContract serializer behavior, which means you can ignore data members by using the opt-out [IgnoreDataMember] attribute
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
[IgnoreDataMember]
public string IsIgnored { get; set; }
}
An opt-in alternative is to decorate every property you want serialized with [DataMember]. The remaining properties aren't serialized, e.g:
[DataContract]
public class Poco
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public string IsIgnored { get; set; }
}
Finally there's also a non-intrusive option that doesn't require attributes, e.g:
JsConfig<Poco>.ExcludePropertyNames = new [] { "IsIgnored" };
Dynamically specifying properties that should be serialized
ServiceStack's Serializers also supports dynamically controlling serialization by providing conventionally named ShouldSerialize({PropertyName}) methods to indicate whether a property should be serialized or not, e.g:
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
public string IsIgnored { get; set; }
public bool? ShouldSerialize(string fieldName)
{
return fieldName == "IsIgnored";
}
}
More examples in ConditionalSerializationTests.cs
For nullable members, you also have the ability to set it to null before serializing.
This is particularly useful if you want to create a single view/api model that is re-used for several API calls. The service can touch it up before setting it on the response object.
Example:
public SignInPostResponse Post(SignInPost request)
{
UserAuthentication auth = _userService.SignIn(request.Domain, true, request.Username, request.Password);
// Map domain model ojbect to API model object. These classes are used with several API calls.
var webAuth = Map<WebUserAuthentication>(auth);
// Exmaple: Clear a property that I don't want to return for this API call... for whatever reason.
webAuth.AuthenticationType = null;
var response = new SignInPostResponse { Results = webAuth };
return response;
}
I do wish there was a way to dynamically control the serialization of all members (including non-nullable) on a per endpoint fashion.

How to read this Json to controller object? Kendo UI grid server filtering

I am trying to filter Kendo UI grid server side filter. The developer tools show this in query string
/Home/GetUsmMessage?{"filter":{"logic":"and","filters" [{"field":"MessageId","operator":"eq","value":1}]},"group":[]} GET 200 application/json
I created a object structure so that I read the structure to object
public ActionResult GetUsmMessage(FilterContainer filter)
{
//Code to read the filter container
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
Object structure for filter container:
public class FilterContainer
{
public List<FilterDescription> filters { get; set; }
public string logic { get; set; }
}
public class FilterDescription
{
public string #operator { get; set; }
public string field { get; set; }
public string value { get; set; }
public List<FilterDescription> filters { get; set; }
public string logic { get; set; }
}
It still gives me a null object when I debug controller function. Please help
Got the answer...I forgot to add type of request as Http post ....
In case of WebApi controller, you could use [FromUri] attributes and GET verb:
public HttpResponseMessage Get(
[FromUri]IEnumerable<SortParameter> sort,
[FromUri]FilterContainer filter,
int take = 10, int skip = 0)

How can I populate a FK field using EF Code First?

I have a class Mailout with a Status that looks like this:
public class Mailout
{
public int Id {get; set; }
public string Name {get; set; }
public MailoutStatus Status { get; set; }
}
public class MailoutStatus
{
public int Id { get; set; }
public string Name { get; set;}
}
When I insert Mailouts and set the Status property, they are inserted correctly. When I fetch them, Status is always null. Since I don't have (and don't want) the status ID on my Mailout class, I have no way to retrieve it after-the-fact. How do I tell EF to populate this field eagerly, rather than lazily?
I'm hoping I can set something up in OnModelCreating() since I want this behavior all the time, not as an option that I can use sometimes by manipulating my LINQ-to-Entities queries.
You need to make your navigation properties virtual.
There is no such option in the ModelBuilder to configure an automatic eager loading of navigation properties in each query. You have to specify it query by query. As a workaround you could encapsulate eager loading in some method or property, for instance in the context:
public class MyContext : DbContext
{
public DbSet<Mailout> Mailouts { get; set; }
public IQueryable<Mailout> MailoutsWithStatus
{
get { return Mailouts.Include(m => m.Status); }
}
// ...
}
And then use in your queries:
context.MailoutsWithStatus.Where(...) ... etc.
Only an idea, it's untested.
Taking from Employee Info Starter Kit - upcoming MVC edition, here is a snippet, that works pretty well, to eager load objects when used:
public class Employee
{
...
public int? ReportsTo { get; set; }
[ForeignKey("ReportsTo")]
public virtual Employee Supervisor { get; set; }
/// <summary>
/// Children object collection of foreign key relation
/// </summary>
public virtual List<Employee> Subordinates { get; set; }
}