Display all blog articles of a specific user - c#

The scenario: I have two tables: UserProfiles and BlogArticles. The blog article is inside UserProfile, so if I would like to get all blog articles of a specific user, I would type something like:
db.UserProfiles.SingleOrDefault(x=> x.UserName == User.Idenity.Name).BlogArticles
However, I would like to do this using the BlogArticles table, that is, I would like to get BlogArticles that come from the same UserProfile, as following:
db.BlogArticles(x=> ...) // these should be from one user only.
Solution1
One way is to do it backwards, as following:
db.UserProfiles.FirstOrDefault(d => d.BlogArticles.FirstOrDefault(x=> x.Id==BlogArticles) != null);
So, given a BlogArticle id, the UserProfile can be found.
However, how would I be able to get a list of articles that come from a particular userprofile using the BlogArticle table?
I've tried
db.BlogArticles.Where(x=> Functions.GetAuthor(x.Id) == User.Identity.Name).ToList()
but I get the following error:
An exception of type 'System.NotSupportedException' occurred in System.Data.Entity.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method 'System.String GetAuthor(Int32)' method, and this method cannot be translated into a store expression.
How can I solve this in a better way?
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public virtual ICollection<BlogArtilce> BlogArticles { get; set; }
public virtual ICollection<Group> Groups { get; set; }
//public DateTime Created = DateTime.Today;
}
[Table("BlogArticle")]
public class BlogArticle
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual string Name { get; set; }
public string Description { get; set; }
public virtual string Contents { get; set; }
public virtual int Views { get; set; }
public virtual string Password { get; set; }
public virtual string Tags { get; set; }
}
public class Group
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; } // this must be an int.
public string Name { get; set; }
public virtual ICollection<BlogArticle> BlogArticles { get; set; }
}

You're making this much more complicated than it needs to be. From your OP you already selected an author and should therefore have access to the author's id and the means to store it.
So, your code could look something like this, assuming that BlogArticles has a property named AuthorId:
int localAuthorId = ???; // assign from wherever you fetched it
// simpler filter:
db.BlogArticles.Where(x => x.AuthorId = localAuthorId).ToList()

Related

EF Core Join Table for One To Many relationship

I have a Database Schema like this.
I am working on gettingDetailByPostID API which needs to return 1 Object as follows.
Guid PostId;
Guid UserId;
String? Username;
String? MediaPath;
int Likes; // count the number of likes of the post
String? Caption;
bool IsLiked;
IEnumerable<Comment>? Comments; // List of comments in the post
I am having difficulty in joining the tables together to get more data from the User and Comment tables. How can I do this with ef core 6.
firsr have a DbSet property for in your db context inherited class which may look like this public DbSet<Post> Posts { get; set; }.
then inject the dbcontext to your required service as constructor injection.
the you can do var post = yourDbContenxt.Posts.FirstOrDefaultAsync(p=>p.PostId==yourPostId);
The best way to do this would be in a single transaction.
I believe you already have configured EF with navigation and you should have an entities like this
public class Post
{
public int post_id { get; set; }
public int user_id { get; set; }
public string caption { get; set; }
public string? media_path { get; set; }
virtual public List<Like> Likes { get; set; }
}
public class Like
{
public int post_id { get; set; }
public int user_id { get; set; }
virtual public Post Post { get; set; }
virtual public UserProfile UserProfile { get; set; }
}
public class UserProfile
{
public int post_id { get; set; }
public int user_id { get; set; }
public string username { get; set; }
virtual public Post Post { get; set; }
virtual public List<Like> Likes { get; set; }
}
If not, you should have a look on the microsoft documentation or on this great tutorial site
If it is configured with navigation (but without lazy loading to avoid infinite loop, and to have an ecological use of your server ressources :) )
Then you can build your object within the same context instanciation such as this short exemple
public class DetailedPost
{
Guid PostId;
Guid UserId;
String? Username;
String? MediaPath;
int Likes; // count the number of likes of the post
String? Caption;
bool IsLiked;
IEnumerable<Comment>? Comments; // List of comments in the post
public DetailedPost GettingDetailByPostID(int id)
{
DbContext context = new DbContext();
UserProfile userprofile = context.UserProfile
.Include(user => user.Posts.Where(p => p.post_id == id)) // Select post by id
.ThenInclude(post => post.Comments) // Include the Comment Db relative to post selected
.Include(user => user.Likes); // Include like db relative to userProfile db
// Return object construction
return new DetailedPost()
{
PostId = userprofile.post_id,
UserId = userprofile.user_id,
Username = userprofile.username,
Caption = userprofile.Posts.FirstOrDefault().Caption,
Likes = userprofiles.Likes.Count(),
};
}
}
I hope it helps !

'Invalid Column Name' Error After Upgrading from Asp.net core 2.0 to 2.1

I've revisited my web site recently and had to upgrade from ASP.net MVC (DBF) core 2.0 to 2.1.
Since doing so I'm getting the following error...
SqlException: Invalid column name 'MovieTitleId'. Invalid column name 'MovieTitleId'.
Yet there is no such field 'MovieTitleId' in any part of my code or db.
The error occurs only when the site is accessing the 'many table' Scenes
(there is a one-to-many relationship set up in the db with FKs.. Movie > Scenes)
This is the Scene class..
public partial class Scene
{
[Key]
public int SceneId { get; set; }
[ForeignKey("TitleId")]
public int? TitleId { get; set; } // foreign key from Movie
[ForeignKey("LocationSiteId")]
public int? LocationSiteId { get; set; }
[ForeignKey("LocationAliasId")]
public int? LocationAliasId { get; set; }
public string Notes { get; set; }
public int? SceneOrder { get; set; }
public string TitleList { get; set; }
public LocationAlias LocationAlias { get; set; }
public LocationSite LocationSite { get; set; }
public Movie Movie { get; set; }
}
And this is the Movie class which on the 'one side' and call Scenes on a typical 'Master/Detail' type web page...
public partial class Movie
{
public Movie()
{
Scenes = new HashSet<Scene>();
}
[Key]
public int TitleId { get; set; }
[Required]
public string Title { get; set; }
[DisplayName("Title")]
public string ParsedTitle { get; set; }
[DisplayName("Year")]
public int? TitleYear { get; set; }
public string ImdbUrl { get; set; }
public string Summary { get; set; }
public bool? ExcludeTitle { get; set; }
public bool? Widescreen { get; set; }
[DisplayName("Title")]
public override string ToString()
{
return Title + " (" + TitleYear + ")";
}
public ICollection<Scene> Scenes { get; set; }
}
The error occurs in the MoviesController.cs...
Movie movie = _context.Movies.Find(id);
ViewBag.Scenes = _context.Scenes
.Where(s => s.TitleId == id)
.Include(s => s.LocationSite)
.Include(s => s.LocationSite.LocationPlace)
.OrderBy(s => s.SceneOrder).ToList();
Everything used to work fine until i upgraded to core 2.1.
I can't even recall there ever being a field called 'MovietitleId' which is actually 'TitleId'.
Is the error msg concatenating the model 'Movie' and column 'TitleId' somehow?
Try adding virtual keyword for your foreign key. Also the ForeignKey Data Annotation should be on that property where you have declared your virtual property just like below. So it should be something like this:
Scene.cs
public int TitleId { get; set; }
[ForeignKey("TitleId")
public virtual Movie Movie { get; set; }
Why virtual?
If you declare your property virtual your virtual property (by default) won't be loaded right away when querying the main object. It will be retrieved from the database ONLY if you try to access it. This is called lazy loading.
If you want to know why to use virtual in detail, you may visit this link: Why are foreign keys in EF Code First marked as virtual?
Hope this helps.

EF Optional Relationships / Nullable / Navigation Table

I solved this, answer below.
I am new to EF and having a lot of difficulty trying to get an optional relationship. I am looking to have a relationship where I have ApiLogItem Model with an UserId property which can be null / anonymous user or a logged in user to track all Api calls. The goal is to have Existing Users who do some create a new object to be linked to that object. I do not want to create new Users every time a new ApiLogItem is created.
I have tried a dozen variations with virtual / foreign key attributes and I am stumped. It works great for null / anonymous user but once I attach an actual user to the ApiLogItem it will not insert. I get this error:
{"Violation of PRIMARY KEY constraint 'PK_AspNetUsers'. Cannot insert
duplicate key in object 'dbo.AspNetUsers'. The duplicate key value is
(09c0d2e2-b003-4be8-a62a-08d7268af58e).\r\nThe statement has been
terminated."}
I have tried following this tutorial but alas no luck.
https://www.learnentityframeworkcore.com/conventions/one-to-many-relationship#targetText=EF%20Core%20will%20create%20a,public%20class%20Author
public class ApiLogItem
{
[Key]
public long Id { get; set; }
[Required]
public int StatusCode { get; set; }
[Required]
public string Method { get; set; }
[MaxLength(45)]
public string IPAddress { get; set; }
public Guid? UserId { get; set; }
public ApplicationUser User { get; set; }
}
public class ApplicationUser : IdentityUser<Guid>
{
[MaxLength(64)]
public string FirstName { get; set; }
[MaxLength(64)]
public string LastName { get; set; }
public List<ApiLogItem> ApiLogItems { get; set; }
}
Error happens when I want to create a new ApiLogItem:
using (ApplicationDbContext _dbContext = new ApplicationDbContext(_optionsBuilder.Options))
{
_dbContext.ApiLogs.Add(apiLogItem);
await _dbContext.SaveChangesAsync();
}
I have reviewed several other stackoverflow issues and none seem to fix. You can find the repository here:
https://github.com/enkodellc/blazorboilerplate
You are calling applicationDbContextSeed.SeedDb(); in your Startup class each time you run, and in your SeedDb method, you are adding a user with a static id 09C0D2E2-B003-4BE8-A62A-08D7268AF58E.
The first time you run, it will create that user; the second time, it will fail because that user (with that id) already exists.
I figured it out. It needs a virtual in the parent and just the id in the child. I need to learn more about EF as it is not intuitive to me. Will post a better answer later today after testing.
public class ApplicationUser : IdentityUser<Guid>
{
[MaxLength(64)]
public string FirstName { get; set; }
[MaxLength(64)]
public string LastName { get; set; }
public ICollection<ApiLogItem> ApiLogItems { get; set; }
}
public class ApiLogItem
{
[Key]
public long Id { get; set; }
[Required]
public int StatusCode { get; set; }
[Required]
public string Method { get; set; }
[MaxLength(45)]
public string IPAddress { get; set; }
public Guid? UserId { get; set; }
}

Using ICollection with MVC & Entity framework

Hi I'm learning to use MVc using Code first method. I'm having trouble understanding the use of ICollection<> with my setup. I have two classes/entitys: 'Restaurant' & 'RestaurantReview' as below:
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string Country { get; set; }
public ICollection<RestaurantReview> Reviews { get; set; }
}
and.....
public class RestaurantReview
{
public int Id { get; set; }
public int Rating { get; set; }
public string Body { get; set; }
public string ReviewerName { get; set; }
public int RestaurantId { get; set; }
}
now whats confusing me is the last property of the Restaurant class. Why is it of type 'ICollection' and uses my RestaurantReview class as a parameter, what does it do, hope I
have made myself clear
It's a definition of one to many relationship.
With that property (sometimes called Navigation Property) Entity Framework will be able to connect Review with Restaurant it was written about. It will also allow you to get Review entities for given Restaurant entity really easily.
You can also remove public int RestaurantId { get; set; } from RestaurantReview class - That column is gonna be generated automatically by EF because of ICollection<RestaurantReview> in Restaurant class.

In ASP.NET MVC how to use another model as property

So I have two model, one is Company, one is Province.
[Table("Company")]
public class Company {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
public int ProvinceID { get; set; }
public ProvinceModel Province{
get {
// ????
}
}
}
public class CompanyContext : MyXsiteContext {
public DbSet<Company> Companies { get; set; }
}
Here is my Province:
[Table("Province")]
public class ProvinceModel {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
}
public class ProvinceContext : MyXsiteContext {
public DbSet<ProvinceModel> Provinces { get; set; }
}
How do I get my Company, which only save the ProvinceID, to reference the Province object so I can refer to the province.name in my view?
It seems like you want to do it similar to how the navigation properties are described here.
So in the link they describe Course -> Department but for you it is Company -> Province.
Also, as an aside, if you are going to reference Province.Name in your view you might run into a Select N+1 problem so that might be something to account for (depending on your specific use case, which I'm not 100% across, just highlighting it as a potential "thing")

Categories