Dapper - Query multiple models - asp.net-core-mvc

My query involves multiple tables and from what I've read on Dapper, I can only find examples, that I understand at least, that query one model.
Below are my 3 classes under the Models folder:
public class User
{
public string UserName { get; set; }
public string UserId { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
public class Date
{
public string UserName { get; set; }
public string UserCode { get; set; }
public string LastLogin { get; set; }
}
public class Photo
{
public class UserName { get; set; }
public string UserId { get; set; }
public string PhotoUrl { get; set; }
}
In my repository I have my connection code and then a method to get all the information I need, however this method is tied to the User model only but I also need to retrieve the photo and when I try to make a compound class so I can the User and Photo models in the view, it gives me an error saying it expects only the User DataView.
public List<User> GetAll()
{
using (SqlConnection cn = new SqlConnection(connectionString))
{
var allResults = cn.Query<User>("SELECT UserName, Email, Phone, (SELECT TOP 1 PhotoPath FROM Photo WHERE User.UserId = Photo.UserId) FROM User)

Your User class does not contain property like PhotoPath - where you expect Dapper put will new/additional value to?
You should create new class (ViewModels/UserAndPhoto.cs for example), which contains all properties you are selecting - then Dapper will read it from database successfully.

Related

ApplicationUser model is missing in mode class field when trying to create new controller

Missing ApplicationUser:
ApplicationUser in model:
So i try to make User Manager by creating controller with ApplicationUser as model, but i can't find it on model class
I got the same problem but I solved it by creating another model class which does not inherit from identity and fetch the data to it and manage it with empty controller.
The model:
public class MyUser
{
public string Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
and in the Controller:
public ActionResult Index()
{
var users = _context.Users.Select(x => new MyUser
{
Email=x.Email,
FirstName=x.FirstName,
Id=x.Id,
LastName=x.LastName,
UserName=x.UserName
}).ToList();
return View(users);
}
then generate your view.

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
}

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/LINQ: Selecting columns from multiple tables?

Models:
public class User
{
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
}
public class Resource
{
[Key]
public int ResourceId { get; set; }
public string ResourceName { get; set; }
public string ResourceDescription { get; set; }
}
public class UserResource
{
[Key, Column(Order=0)]
public int UserId { get; set; }
[Key, Column(Order=1)]
public int ResourceId { get; set; }
public int ResourceQuantity { get; set; }
}
I want to select "ResourceName" from Resource model and "ResourceQuantity" from UserResource model for a given "UserId". Also, once selected, do I need a brand new model to carry only those two specified columns?
Also note that UserResource model has a composite key so I am confused as to how to make the join... Is this right?
var userResources =
from r in imDB.Resources
join ur in imDB.UserResources
on r.ResourceId equals ur.ResourceId
select new { r.ResourceName, ur.ResourceQuantity };
Hence you're using Code first you can create your models are as below by using EF conventions.
public class User {
public int Id { get; set; }
public string UserName { get; set; }
public virtual ICollection<Resource> Resources { get; set; }
}
public class Resource {
public int Id { get; set; }
public string ResourceName { get; set; }
public int ResourceQuantity { get; set; }
public virtual ICollection<User> Users {get;set;}
}
Then EF will generate your junction table is as UsersResources.You don't need to create additional model as you did.EF will look after that.
When using POCOs with EF, if you mark your navigation properties as
virtual you can use additional EF supports like Lazy Loading. So in
general use a virtual keyword in navigation properties considered to
be a good practice.
UPDATE
You may try something like below:
Method 1 : Method based syntax
imDB.Resources.Where(r => r.Users.Any(u => u.UserId == userId))
Method 2 : Query based syntax
from r in imDB.Resources
from u in r.Users
where u.UserId == userId
select r;
I hope this will help to you.

Create with ViewModel that has two related entities

I have the properties for two entities in a ViewModel. The two entities are both related to one another, so for example, User and Posts. Each User can have multiple Posts, and Many Posts can belong to a single user (one-to-many).
The aim from my ViewModel is to allow the addition of a User and a Post on the same form. So my ViewModel looks something like this:
public class CreateVM
{
[Required, MaxLength(50)]
public string Username { get; set; }
[Required, MaxLength(500), MinLength(50)]
public string PostBody { get; set; }
// etc with some other related properties
}
In my Controller on the Create Method I have something like this:
[HttpPost]
public ActionResult Create(CreateVM vm)
{
if (ModelState.IsValid)
{
User u = new User()
{
Username = vm.Username,
// etc populate properties
};
Post p = new Post()
{
Body = vm.PostBody,
// etc populating properties
};
p.User = u; // Assigning the new user to the post.
XContext.Posts.Add(p);
XContext.SaveChanges();
}
}
It all looks fine when I walk through it through the Debugger, but when I try to view the post, its User relationship is null!
I also tried
u.Posts.Add(p);
UPDATE:
My Post class code is as follows:
public class Post
{
[Key]
public int Id { get; set; }
[Required, MaxLength(500)]
public string Body { get; set; }
public int Likes { get; set; }
[Required]
public bool isApproved { get; set; }
[Required]
public DateTime CreatedOn { get; set; }
[Required]
public User User { get; set; }
}
But that also did not work. What am I doing wrong?
Problem is that EF can not lazy load the User property because you haven't made it virtual.
public class Post
{
[Key]
public int Id { get; set; }
[Required, MaxLength(500)]
public string Body { get; set; }
public int Likes { get; set; }
[Required]
public bool isApproved { get; set; }
[Required]
public DateTime CreatedOn { get; set; }
[Required]
public virtual User User { get; set; }
}
If you know beforehand that you are going to access the User property of the post you should eager load the User related to the post.
context.Posts.Include("User").Where(/* condition*/);

Resources