Dapper - Object reference not set to an instance of an object - sql

I've recently been playing around with dapper, but I've run into a bit of a problem regarding getting data from other tables.
My database has two tables, Users and Post. I've created two classes for these tables.
My User class
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime JoinDate { get; set; }
}
My Post class
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public DateTime PublishDate { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
This is my query to fetch all the post data from my database, and also get the Username who created the post.
public IEnumerable<Post> GetPosts()
{
string myQuery = "SELECT p.Title, p.PublishDate, p.PostId, p.UserId, u.Username FROM Post p INNER JOIN Users u ON p.UserId = u.UserId";
sqlConnection.Open();
var posts = sqlConnection.Query<Post>(myQuery);
return posts;
}
Here is my view code where I want to display the information:
#model IEnumerable<MvcDapperIntro.Models.Post>
#{
ViewBag.Title = "Posts";
}
#foreach (var post in Model)
{
<h3>#post.Title</h3>
<p>#post.PublishDate.ToString("dd/MM/yyyy")</p>
<p>#post.User.Username</p>
}
However, when I run my code, I get the 'Object reference not set to an instance of an object' error. Is this because I shouldn't be using:
public User User { get; set; }
to access the username property, or should I create a new class with a username field. Any input would be appreciated.

I get the 'Object reference not set to an instance of an object' error
I bet the issue is on this line: <p>#post.User.Username</p> and that is because you did not map the User object. You should change this code:
var posts = sqlConnection.Query<Post>(myQuery);
to this:
var posts = sqlConnection.Query<Post, User, Post>(
myQuery,
(p, u) => { p.User = u; return p; }
);

Related

Entity Framework virtual ICollections

I'm new to .NET Core Entity Framework (code-first), but do daily progress.
I am now stuck on a probably small mistake and can't go on.
I have a class list that I am trying to fill and in there there is a virtual ICollection from another list, to be filled at the same time.
These are my classes
public class UgInfo
{
public Guid UserGroupId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<UInfo> UInfo { get; set; }
}
public class UInfo
{
public string UserEmail { get; set; }
public string UserName { get; set; }
}
This is where the error occurs:
Invalid Initializer member declarator"
Code:
var ugList = (from ug in _context.Usergroups
join uug in _context.UserUsergroup on ug.UserGroupId equals uug.UsergroupId
join u in _context.Users on uug.UserId equals u.UserId
select new UgInfo
{
UserGroupId = uug.UsergroupId,
Description = ug.Description,
Name = ug.Name,
new UInfo //Error
{
UserName = u.UserName,
UserEmail = u.Email
}
}).ToList();
return ugList;
Could there be anyone who can help a beginner?
Well, you're missing the member name you're attempting to initialize, for one. Then, you need to initialize it with a collection type, not a single UInfo instance:
...
Name = ug.Name,
UInfo = new List<UInfo>
{
new UInfo
{
...
}
}
You have ICollection<UInfo> as property, and you are using new UInfo in the code. It should be new List<UInfo>.

How to use Raven LoadDocument

I'm having trouble querying RavenDB with even the simplest of queries, probably I'm doing something wrong, but after a few hours I just can't see it anymore. I've googled almost anything I can think of..
I have these entities:
public class User
{
public string Id { get; set; }
public string DisplayName { get; set; }
public string RealName { get; set; }
public string Email { get; set; }
public string PictureUri { get; set; }
public List<Comment> Comments { get; set; }
public List<Role> Roles { get; set; }
}
public class NewsItem
{
public string Id { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public DateTime Created { get; set; }
public string UserId { get; set; }
public List<Tag> Tags { get; set; }
public List<Comment> Comments { get; set; }
public List<WebImage> Images { get; set; }
}
I want to query these so I get a list of newsItems, but with the user information alongside it. So I read the docs and tried the LoadDocument feature, the index:
public class NewsItemIndexWithComments : AbstractIndexCreationTask<NewsItem, NewsItemIndexWithComments.Result>
{
public class Result
{
public string AuthorName { get; set; }
}
public NewsItemIndexWithComments()
{
Map = newsItems => from newsItem in newsItems
select new
{
AuthorName = LoadDocument<User>(newsItem.UserId).DisplayName
};
}
}
Which I try to use like:
var result = _documentSession.Query<NewsItemIndexWithComments.Result, NewsItemIndexWithComments>().AsProjection<NewsItemIndexWithComments.Result>().ToList();
Now I get the number of documents in my list, but the AuthorName is always null. If I don't use the AsProjection method, I won't get any results. Can anyone show me a proper example on which I can experiment further?
Thanks.
_ edit:
That helped a lot, thanks :) Now for step two, I'm sorry if I'm being a bit newbish, but you'll have to start somewhere. In the newsitems there are comments, in these comments there is another reference to the userid. You can probably guess what I want to do: I want the user info for the comments with the comments as well.
new Index:
public class NewsItemIndexWithComments : AbstractIndexCreationTask<NewsItem, NewsItemIndexWithComments.Result>
{
public class Result : NewsItem
{
public string AuthorName { get; set; }
public string AuthorId { get; set; }
}
public NewsItemIndexWithComments()
{
Map = newsItems => from newsItem in newsItems
let user = LoadDocument<User>(newsItem.UserId)
select new
{
AuthorName = user.DisplayName,
AuthorId = user.Id,
};
Store(x => x.AuthorName, FieldStorage.Yes);
Store(x => x.AuthorId, FieldStorage.Yes);
}
}
Comment class:
public class Comment
{
public string Id { get; set; }
public string Text { get; set; }
public string UserId { get; set; }
public string User { get; set; }
public DateTime Created { get; set; }
}
How can I query the comments and expand the results for that? Or is it better to create a new index just for the comments and get the user info analog to the solution above?
You're almost there, you just need to store the field you are projecting. Add this to the index constructor, after the map.
Store(x=> x.AuthorName, FieldStorage.Yes);
This is because you want it returned and available for AsProjection to find. If you just wanted to use the author name in a where or orderby, you wouldn't need it.
If you just want to include the comments in your AsProjection, you can simply index the entire object along.
Note that indexing a custom object will mean that you're not able to query on it using a .Where(). RavenDB can only query on flattened results (ints, decimals, strings, dates).
In order to, for instance, query on the title, you will need to create a seperate Property public string Title { get; set; } and map it with Title = newsItem.Title.
public class NewsItemIndexWithComments : AbstractIndexCreationTask<NewsItem, NewsItemIndexWithComments.Result>
{
public class Result : NewsItem
{
public string AuthorName { get; set; }
public string AuthorId { get; set; }
public List<Comment> Comments { get; set; }
}
public NewsItemIndexWithComments()
{
Map = newsItems => from newsItem in newsItems
let user = LoadDocument<User>(newsItem.UserId)
select new
{
AuthorName = user.DisplayName,
AuthorId = user.Id,
Comments = newsItem.Comments.
};
Store(x => x.AuthorName, FieldStorage.Yes);
Store(x => x.AuthorId, FieldStorage.Yes);
Store(x => x.Comments, FieldStorage.Yes);
}
}

CodeFirst - Update single property

We are using EF5, Code First approach to an MVC4 app that we're building. We are trying to update 1 property on an entity but keep getting errors. Here's what the class looks like which the context created:
public partial class Room
{
public Room()
{
this.Address = new HashSet<Address>();
}
public int RoomID { get; set; }
public Nullable<int> AddressID { get; set; }
public Nullable<int> ProductVersionID { get; set; }
public string PhoneNumber { get; set; }
public string AltPhone { get; set; }
public string RoomName { get; set; }
public string Description { get; set; }
public string Comments { get; set; }
public string Notes { get; set; }
public virtual ICollection<Address> Address { get; set; }
}
Here's our ViewModel for the view:
public class RoomDetailsViewModel
{
//public int RoomID { get; set; }
public string RoomName { get; set; }
public string PhoneNumber { get; set; }
public string AltPhone { get; set; }
public string Notes { get; set; }
public string StateCode { get; set; }
public string CountryName { get; set; }
public string ProductVersion { get; set; }
public int PVersionID { get; set; }
public List<SelectListItem> ProductVersions { get; set; }
public Room Room { get; set; }
}
Here's the Controller Action being called on "Save":
[HttpPost]
public virtual ActionResult UpdateRoom(RoomDetailsViewModel model)
{
var db = new DBContext();
bool b = ModelState.IsValid;
var rooms = db.Rooms;
var rm = rooms.Where(r => r.RoomID == model.Room.RoomID).Single();
//List<Address> address = db.Addresses.Where(a => a.AddressID == rm.AddressID).ToList<Address>();
rm.ProductVersionID = model.PVersionID;
//rm.Address = address;
db.Entry(rm).Property(r => r.ProductVersionID).IsModified = true;
//db.Entry(rm).State = System.Data.EntityState.Modified;
db.SaveChanges();
return View("RoomSaved", model);
}
All this view does is display data and allow the user to change the Product Version (from a SelectList), so, in the Room Entity, all we are updating is the ProductVersionID property, nothing else. We can get the data to display properly but when we click "save", we get this error:
An object of type 'System.Collections.Generic.List`1[[Models.Address,
Web.Mobile.TestSite, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]' cannot be set or removed from the Value
property of an EntityReference of type 'Models.Address'.
As you can see by the Controller Action, we've tried several different things but all seem to produce this error. I've tried to populate the model.Room.Address collection with an Address, without, but still get this error.
I read this StackOverflow article and this article as well but neither have solved my problem.
ANY help with this would be greatly appreciated!
After hours and hours of digging, turns out that EF did not import some of the PK's for my DB tables. What tipped me off to this was on the Room class, the PK RoomID did not have the [Key] attribute on it. I tried to reimport the table through the edmx but it never came through as a key (even though it's clearly marked PK in the DB). So, to get around it, I created a partial class of my DBContext and override the OnModelCreating event and included the key, like so:
public partial class DBContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Models.Room>().HasEntitySetName("Rooms");
modelBuilder.Entity<Models.Room>().HasKey(r => r.RoomID);
}
}
Once this was done, the Action saved the record as hoped.
I hope this helps someone else!

asp.net mvc 3 EF query from one to many relationship

I am new to asp.net mvc and i have problems that i think i would solve them very easy with asp.net web forms. However the project have to be in mvc, so here is the problem.
I got X tables
table1 Users
int user_ID
string username
table2 Friends
int friendshipID
int user_ID
int friend_ID
In table 2, user_ID represents the current user that is logged in. friend_ID represents ids from his friends. Its one to many relationship.
Now what i want to do, is, in user/details/ID view, show all friends of that user.
The query that i want to make is: first select the friend_IDs from table2 where user_ID=id(from querystring), then select every username from table1 where user_ID = friend_ID.
I think this is really easy in SQL, but dont know how to do it with the mvc syntax.
The controller:
//
// GET: /User/Details/5
public ViewResult Details(int id)
{
User user = db.Users.Find(id);
return View(user);
}
The view:
#model Social2.Models.User
<div class="display-label">Friends</div>
<div class="display-field">
#foreach (var friend in #Model.Friends)
{
#friend.User.username;
}
</div>
The view returns wrong results.
Models
public partial class User
{
public User()
{
this.Albums = new HashSet<Album>();
this.Friends = new HashSet<Friend>();
this.Messages = new HashSet<Message>();
this.Posts = new HashSet<Post>();
this.Groups = new HashSet<Group>();
}
public int user_ID { get; set; }
public System.Guid user_UniqueID { get; set; }
public string username { get; set; }
public virtual ICollection<Album> Albums { get; set; }
public virtual aspnet_Users aspnet_Users { get; set; }
public virtual ICollection<Friend> Friends { get; set; }
public virtual ICollection<Message> Messages { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public virtual ICollection<Group> Groups { get; set; }
}
and from friends table
public partial class Friend
{
public int friendship_ID { get; set; }
public int user_fr_ID { get; set; }
public int friend_ID { get; set; }
public virtual User User { get; set; }
}
also the context
public partial class ASPNETDBEntities : DbContext
{
public ASPNETDBEntities()
: base("name=ASPNETDBEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Album> Albums { get; set; }
public DbSet<aspnet_Users> aspnet_Users { get; set; }
public DbSet<Friend> Friends { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<Message> Messages { get; set; }
public DbSet<Picture> Pictures { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<sysdiagram> sysdiagrams { get; set; }
public DbSet<User> Users { get; set; }
}
As the Friends list property is virtual it will not be included with your query. Try using below query to include the Friends.
public ViewResult Details(int id)
{
User user = db.Users.Include("Friends").FirstOrDefault(u => u.user_ID == id);
//Also for each friend get the User:
foreach (var friend in user.Friends.ToList())
{
friend.User = db.Users.Find(friend.friend_ID);
}
return View(user);
}
View:
<table>
#foreach (var friend in #Model.Friends)
{
<tr>
#Html.DisplayFor(modelItem => friend.User.username)
</tr>
}
</table>
Your model classes doesn't appear to be following the convention for the Entity keys. The fields "user_ID" and "friendship_ID" should be UserId and FriendId. Or if you want to key them like that annotate them with [key] attribute.
Make the ViewModel class of your own. Retrieve the data from database and build the model class object. Pass this model class to view i.e. create your view based on this model class.

Entity Framework Creates New Record in Table I Didn't Reference when Inserting Into Other Table

In this website, users can register under a username and password, and can also post comments on articles. The models are pretty straightforward:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsAdmin { get; set; }
public DateTime JoinDate { get; set; }
public string AvatarPath { get; set; }
public string EmailAddress { get; set; }
}
public class ArticleComment
{
public int Id { get; set; }
public int ArticleId { get; set; }
public int UserId { get; set; }
public string CommenterName { get; set; }
public string Message { get; set; }
public DateTime CommentDate { get; set; }
public User User { get; set; }
}
Entity Framework correctly made the foreign key relationship between UserId on ArticleComment and Id on User when the database was created using code-first.
Here's my code for when a user posts a new comment:
public JsonResult SubmitComment(int articleId, string comment)
{
var response = new JsonResponse();
var currentUser = _userRepository.GetUserByUsername(User.Identity.Name);
//...
var newComment = new ArticleComment
{
ArticleId = articleId,
CommentDate = DateTime.Now,
CommenterName = currentUser.Username,
UserId = currentUser.Id,
User = currentUser,
Message = comment,
};
try
{
_articleRepository.Insert(newComment);
}
catch (Exception e)
{
response.Success = false;
response.AddError("newComment", "Sorry, we could not add your comment. Server error: " + e.Message);
return Json(response);
}
response.Success = true;
response.Value = newComment;
return Json(response);
}
The values that make up the newComment object all appear to be correct, and the Insert method in my Article repository class is straight and to the point:
public void Insert(ArticleComment input)
{
DataContext.ArticleComments.Add(input);
DataContext.SaveChanges();
}
But once this happens, poof: a new record in my Users table appears along with the new record in ArticleComments. All of the info in the new Users record is duplicated from that user's existing record - the only difference is the value for the primary key Id. What gives?
In addition to my comment, you need to make sure that both _userRepository and _articleRepository are using the same DbContext instance.
Either that, or you can try this:
var newComment = new ArticleComment
{
ArticleId = articleId,
CommentDate = DateTime.Now,
CommenterName = currentUser.Username,
UserId = currentUser.Id,
// User = currentUser, let the UserId figure out the User, don't set it yourself.
Message = comment,
};