How to create one-to-many related object in ASP.NET Web API? - asp.net-web-api

I have two entities
public class Tax
{
public int Id { get; set; }
public string Name { get; set; }
public int ClientId { get; set; }
public Client Client { get; set; }
}
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Tax> Taxes { get; set; }
}
and in this method, I want to create a relationship between Client and Tax using ClientId, but i am getting The Client field is required error on client side, so I want to ignore field Client.
My question is how to ignore fielf client or if I'm doing something wrong, then how to create one-to-many relationship in Post method? (I'm new to ASP.NET so sorry if this is a stupid question.)
[HttpPost]
public IActionResult Post(Tax tax)
{
tax.Client = (from c in context.Clients
where c.Id == tax.ClientId
select c).FirstOrDefault<Client>();
context.Taxes.Add(tax);
context.SaveChanges();
return Created("api/taxes", tax);
}

you just need to make ClientId nullable. It will do the same as an optioanal.
public int? ClientId { get; set; }
public Client Client { get; set; }
or if you use net 6 you will have to make Client nullable too
public int? ClientId { get; set; }
public Client? Client { get; set; }
but you can remove nullable option from project to avoid all this extra problems forever
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<!--<Nullable>enable</Nullable>-->
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
in this case, if tax has a ClientId already, you only need
context.Taxes.Add(tax);
context.SaveChanges();

Related

Automapper Many to Many Mapping Including Joining Table Data

I am developing an ASP.Net Core Web API using EF Core Code First (C#) and SQL Server.
I have a fairly simple scenario which I just cannot figure out. I have a Form entity and a Site entity. Each Form can have many Sites and each Site can be in many Forms. To enable this I have a SiteForm joining table. For each Site associated with a Form there is a Leaving Date field. So my SiteForm class looks like this:
public class SiteForm
{
public Guid SiteId { get; set; }
public Site Site{ get; set; }
public Guid FormId { get; set; }
public Form Form{ get; set; }
public DateTime? LeavingDate { get; set; }
}
My Form's Data Transfer Object (FormDto) is as follows:
public class FormDto
{
public Guid Id { get; set; }
...
public ICollection<LinkedSiteDto> LinkedSites { get; set; }
= new List<LinkedSiteDto>();
}
And my LinkedSiteDto is like this:
public class LinkedSiteDto
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Ident { get; set; }
public DateTime? LeavingDate { get; set; }
}
Having populated the database I can get the Sites for each Form using the following mapping:
CreateMap<Form, FormDto>()
.ForMember(dto => dto.LinkedSites, opt => opt.MapFrom(
form => form.SiteForms.Select(sf => sf.Site).ToList()));
I just cannot figure out how I would include the LeavingDate value from each joining table entry? Any suggestions would be very gratefully received.

Updating one of the related entity

I'm developing bulletin board system (as part of my training of asp.net mvc). I have a basic understanding of data modeling, but I have a doubt the way I've created my model. The core logic is to post ad with the following categories realty, auto and service. Initially I tried to use TPH approach, but then faced with problem of binding my models and automapper configuration. Now I think to use zero or one relationship.
I have a Ad model:
public class Ad
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual Realty Realty { get; set; }
public virtual Auto Auto { get; set; }
public virtual Service Service { get; set; }
}
Realty:
public class Realty
{
[Key]
[ForeignKey("Ad")]
public int AdID { get; set; }
public string Type { get; set; }
public string NumberOfRooms { get; set; }
public virtual Ad Ad { get; set; }
}
Auto and service models have the same foreign key as the Realty model.
My db context:
public DbSet<Ad> Ads { get; set; }
public DbSet<Realty> Realties { get; set; }
public DbSet<Auto> Autos { get; set; }
public DbSet<Service> Services { get; set; }
I need update Ad model with one related model only. I'm using scaffolded controller action, which includes all related models:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "Title,Descirpiton,Realty,Auto,Service")] Ad ad)
{
if (ModelState.IsValid)
{
db.Ads.Add(ad);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.ID = new SelectList(db.Autos, "AdID", "CarType", ad.ID);
ViewBag.ID = new SelectList(db.Realties, "AdID", "Type", ad.ID);
ViewBag.ID = new SelectList(db.Services, "AdID", "ServiceType", ad.ID);
return View(ad);
}
The problem, that it makes possible to post Ad with all related models together. Before diving deep I wanted to ensure that I'm on a right way of doing this.
Thanks.
You're close. Based on what it looks like you're trying to do you should be using a table-per-type model. You create the base (Ad) and then inherit from it to create the sub-types.
public class Ad
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
[Table("Realty")]
public class Realty : Ad
{
public string Type { get; set; }
public string NumberOfRooms { get; set; }
}
Your context remains the same. You can now create the appropriate sub-type when you know what kind of ad is being created.
var ad = new Realty();
ad.Title = "...";
ad.Description = "...";
ad.Type = "...";
ad.NumberOfRooms = "...";
You can retrieve specific ad types by using the specific type on the context.
db.Realty.ToList();
Or you can retrieve all the ads and interrogate the types as you loop over them.
var ads = db.Ads.ToList();
foreach(var ad in ads)
{
if(ad is Realty)
// do Realty stuff
else if (ad is Auto)
// do Auto stuff
}

ASP.NET Model Relationship

I'm currently learning ASP.NET MVC and Web API.
I'm trying to create a User Model. Users can have any number of UserContacts. UserContacts reference the User it is a contact of and the User who is the contact. I have made a model called UserContact because attached to this Model is additional information.
public class User
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserContact
{
public int UserContactID { get; set; }
public int UserID { get; set; }
[ForeignKey("UserID"), Column(Order = 0)]
[Required]
public User User { get; set; }
public int ContactID { get; set; }
[ForeignKey("ContactID"), Column(Order = 1)]
[Required]
public User Contact { get; set; }
public DateTime ContactSince { get; set; }
}
So this gives me an error referring to cascading Delete. How do I set up a relationship like this where two foreign keys point to the same Model type? I have yet to grasp Entity Framework syntax as well. If I don't have an ICollection of UserContacts in the User model, does this hinder my ability to grab the UserContacts associated with that User?
When you have a foreign key and the foreign key columns are not nullable(means,required). EF will automatically tries to enable cascading delete on the relationsip. In your case, it will try to enable Cascading delete for both the foreign key columns and both of them points to the same user table! That is the reason you are getting this error. What if you have a UserContact record with Both UserId and ContactID points to the same User record. Cascading delete is confused now :)
Also, since one user can have more than one Contacts, We need a Contacts property on the User table to represent that. This will be a collection of UserContact's. Also this user can be a a contact of many other people. So Let's create another property for that.
public class User
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<UserContact> Contacts { set; get; }
public ICollection<UserContact> ContactOf { set; get; }
}
public class UserContact
{
public int UserContactID { get; set; }
public int UserID { get; set; }
public User User { get; set; }
public int ContactID { get; set; }
public User Contact { get; set; }
public DateTime ContactSince { get; set; }
}
And in your DbContext class, We can configure the foreign key relation ships and tell EF to disable cascade delete using fluent configuration inside the overridden OnModelCreating method. The below code will disable cascading delete on both the the relationships. But for your error to go away. disabling on one foreign key is enough.
public class YourDbContext: DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<UserContact>()
.HasRequired<User>(g=>g.User)
.WithMany(g=>g.Contacts)
.HasForeignKey(g=>g.UserID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<UserContact>()
.HasRequired<User>(g => g.Contact)
.WithMany(g => g.ContactOf)
.HasForeignKey(g => g.ContactID)
.WillCascadeOnDelete(false); // this one is not really needed to fix the error
base.OnModelCreating(modelBuilder);
}
public DbSet<User> Users { set; get; }
public DbSet<UserContact> UserContacts { set; get; }
}
This will create the tables like you wanted with the necessary foreign keys.
There is not enough information for EF to figure out the relationships on the other side, so yes, you need collections. You can use the InverseProperty annotation to clarify (or fluent api statements):
public class User
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[InverseProperty("User")]
public Virtual ICollection<UserContact> Users{ get; set; }
[InverseProperty("Contact")]
public Virtual ICollection<UserContact> Contacts { get; set; }
}
public class UserContact
{
public int UserContactID { get; set; }
public int UserID { get; set; }
[ForeignKey("UserID"), Column(Order = 0)]
[Required]
public User User { get; set; }
public int ContactID { get; set; }
[ForeignKey("ContactID"), Column(Order = 1)]
[Required]
public User Contact { get; set; }
public DateTime ContactSince { get; set; }
}
http://www.entityframeworktutorial.net/code-first/inverseproperty-dataannotations-attribute-in-code-first.aspx

How to Retrieve Systems Properties from Azure Mobile Services .Net Backend

How can I retrieve the System Properties of "__createdAT" and "__updatedAT" from an Azure Mobile Service Table (.Net Backend). I see that these values exist on the Azure SQL Server.
This is my backing Model Class
public class Customer : EntityData
{
public string CustomerName { get; set; }
public string CustomerEmail { get; set; }
public string PhoneNumber { get; set; }
public string CardUid { get; set; }
}
And I can confirm that the columns are created at the Azure Mobile Services backing SQL Backend
And here is my Xamarin Android model class
public class Customer
{
public string id { get; set; }
[JsonProperty(PropertyName = "customerName")]
public string CustomerName { get; set; }
[JsonProperty(PropertyName = "customerEmail")]
public string CustomerEmail { get; set; }
[JsonProperty(PropertyName = "phoneNumber")]
public string PhoneNumber { get; set; }
[JsonProperty(PropertyName = "cardUid")]
public string CardUid { get; set; }
[CreatedAt]
public DateTime EnrollmentDate { get; set; }
[UpdatedAt]
public DateTime LastTransactionDate { get; set; }
}
However, this does not return the values, here is what it returns to the Xamarin.Android client
Even the web Try it out does not return the CreatedAT and UpdatedAT column, how can I return these columns to the clients.
Thanks
In the client SDK you need to specify that you want the system properties returned (they are not by default).
In C# you would do something like this:
customerTable = myAzClient.GetTable<Customer>;
customerTable.SystemProperties = MobileServiceSystemProperties.CreatedAt | MobileServiceSystemProperties.UpdatedAt;
var customers = await customerTable.ReadAsync();
You can see more in Carlos' blog post
Try renaming you CreatedAt and UpdatedAt Properies in your client side DTO classes.
public class Customer
{
....
[CreatedAt]
public DateTime CreatedAt{ get; set; }
[UpdatedAt]
public DateTime UpdatedAt{ get; set; }
}
This worked for me the last time

Entity Framework POCO Relationships

I am trying to implement code-first approach of entity framework. I have four entities UserInfo, Client, Admin and Account. I want relationships as:
Each Client has a UserInfo
Each Admin has a `UserInfo
Each Account is linked with a User(UserInfo)
Assuming these things i wrote the POCO models. With the relationships i want, is it correct ?Am i missing something?
public class UserInfo
{
public int UserInfoID { get; set; }
public Name Name { get; set; }
public Address Address { get; set; }
public Contact Contact { get; set; }
}
public class Admin
{
public int AdminID { get; set; }
public int UserInfoID { get; set; }
[ForeignKey("UserInfoID")]
public virtual UserInfo UserInfo { get; set; }
}
public class Client
{
public int ClientID { get; set; }
public CompanyDetails CompanyDetails { get; set; }
public int UserInfoID { get; set; }
[ForeignKey("UserInfoID")]
public virtual UserInfo UserInfo { get; set; }
}
public class Account
{
public int AccountID { get; set; }
[Required, Column("Balance"), Display(Name = "Account Balance")]
public double Balance { get; set; }
public int UserInfoID { get; set; }
[ForeignKey("UserInfoID")]
public virtual UserInfo UserInfo { get; set; }
}
What you have appears to be correct based on your requirements however I personally prefer the Entity Framework Model Builder when configuring your entities with Code First.
Using the model builder means that you don't have any attributes on your POCO entities which in turn means that you don't need an EF reference to use the entities.
Take a look at my article here for some more info on how to use the modelbuilder : http://blog.staticvoid.co.nz/2012/07/entity-framework-navigation-property.html

Resources