c# how to find an id from an element in database - c#

How i get the id from the value english, searching all time without any answer.
Thanks for helping
test.CourseId = await _context.Course.FirstOrDefaultAsync(m => m.Schulfach == english);

Your code retrieves the whole object. You need to access a single property of this object:
var course = await _context.Course.FirstOrDefaultAsync(m => m.Schulfach == english);
if (course != null)
{
test.CourseId = course.CourseId;
}

Related

EF Core - Modify realations without loading entity

I was trying to implement a function that will let a user like a comment. If the user has already liked it, it can't be liked again and vice versa.
This is what it looks like:
public async Task<ActionResult<CommentResponse>> LikeComment(LikeComment like)
{
if (like.HasNullProperty())
return BadRequest("Missing properties!");
var comment = await commentService.GetCommentWithLikes((int) like.CommentId);
if(comment is null)
return NotFound($"No comment with id {like.CommentId} was found");
try
{
var userId = User.GetUserID();
comment = await commentService.LikeComment(comment, userId, (bool)like.Liked);
return comment is not null ? Ok(comment.GetCommentResponse((bool)like.Liked)) : StatusCode(304);
}
catch(Exception e)
{
return StatusCode(500, $"Error while trying to {((bool)like.Liked ? "like" : "dislike")} comment");
}
}
Relevant functions:
public async Task<Comment> GetCommentWithLikes(int id) => await blogContext.Comments.IncludeLikes().FirstOrDefaultAsync(x => x.Id == id);
public static IQueryable<Comment> IncludeLikes(this IQueryable<Comment> source)
=> source.Select(x => new Comment
{
Id = x.Id,
ArticleId = x.ArticleId,
CreatedById = x.CreatedById,
CreatedAt = x.CreatedAt,
Likes = x.LikedBy.Count,
Text = x.Text,
});
And the main like logic:
public async Task<Comment> LikeComment(Comment comment, string userId, bool liked)
{
var user = new User { Id = userId };
var hasLiked = await blogContext.Comments.Where(x => x.Id == comment.Id && x.LikedBy.Any(x => x.Id == user.Id)).FirstOrDefaultAsync() is not null;
Action action = null;
if (!hasLiked && liked)
{
action = () => comment.LikedBy.Add(user);
comment.LikedBy = new List<User>();
comment.Likes++;
}
else if (hasLiked && !liked)
{
action = () => comment.LikedBy.Remove(user);
comment.LikedBy = new List<User> { user };
comment.Likes--;
}
if (action is null)
return null;
blogContext.Attach(user);
blogContext.Attach(comment);
action();
await blogContext.SaveChangesAsync();
return comment;
}
The idea was to not load the whole likedBy relation, but still notify EF Core that i have added or removed one user. Therefore i modify the Comment, then attach it so EF Core tracks the changes to the likedBy relation. Interestingly, it works fine when liking a comment. However, when disliking, i get an rrror that the comment is already attached. Using .AsNoTracking() in the GetCommentsWithLikes function didn't help.
The instance of entity type 'Comment' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
This is the comment passed to the like func when linking (works):
This is the one when disliking (only diff is the like count...):
And this is it right before the failing attach:
Maybe someone knows the reason for this behaviour and can help me or suggest a different approach :)
Thanks
Using .AsNoTracking() in the GetCommentsWithLikes function didn't help
Due to the used projection, that function is already implicitly no tracking. It is the following call
var hasLiked = await blogContext.Comments
.Where(x => x.Id == comment.Id && x.LikedBy.Any(x => x.Id == user.Id))
.FirstOrDefaultAsync() is not null;
which is adding a Comment instance to the change tracker when the result is not null.
Since you don't need that instance and are just checking for existence, use the following instead which doesn't involve entity instances, but pure server side query:
var hasLiked = await blogContext.Comments
.AnyAsync(x => x.Id == comment.Id && x.LikedBy.Any(x => x.Id == user.Id));

Linq code doesn't return correct record

I have a table named dbo.EmployeeType with three records:
PK_EmployeetypeID EmployeeTypeName
1 Project Manager
2 Business Analyst
3 Developer
I have this piece of Linq code:
public static string GetTypeByID(int id)
{
using (ProjectTrackingEntities1 db = new ProjectTrackingEntities1())
{
var type = db.EmployeeTypes.Select(o => new LOOKUPEmployeeType
{
PK_EmployeeTypeID = id,
EmployeeTypeName = o.EmployeeTypeName
});
return type.FirstOrDefault().EmployeeTypeName;
}
}
No matter what id I send to it, it returns Project Manager, and I'm confused as to why.
You need to apply a filter, otherwise you're just returning the first record and hard coding the ID. Try this:
public static string GetTypeByID(int id)
{
using (ProjectTrackingEntities1 db = new ProjectTrackingEntities1())
{
//Here we apply a filter, the lambda here is what creates the WHERE clause
var type = db.EmployeeTypes
.FirstOrDefault(et => et.PK_EmployeeTypeID == id);
if(type != null)
{
return type.EmployeeTypeName;
}
else
{
return "";
}
}
}
Note that using FirstOrDefault means if there are no matches, or multiple matches, type will be null and you will get an empty string returned.
Set a breakpoint on type = ... and inspect it. You have no Where in there so you get all - and Select just makes LOOKUPEmployeeTypes out of all of them.
FirstOrDefault then returns the first of those 3 which is always the ProjManager
Fix:
var type = db
.EmployeeTypes
.Where( o => o.Id == id)
.Select(o => new LOOKUPEmployeeType
{
PK_EmployeeTypeID = id,
EmployeeTypeName = o.EmployeeTypeName
});
In your code you only return the first value. You need to tell EF which value you need to return.
Let us assume you need the value with Id=2. Instead of Select(), use Single(x => x.Id == 2) or First(x => x.Id == 2).

Return Object with different scope based on Conditional Logic (C#)

I've been a developer (also in a professional capacity) for a little while now and really never focused on clean / well structured code. As completely self taught I guess I'm missing some of the fundamentals. Reading books never fills the gaps. So I hope to get some great experience from this post.
So to the point, I have a method that returns an object (Campaign) based on conditional logic.
If I can get the object via the "CampaignViewMode" then it must have been "viewed" so therefore GET
ELSE Get last inserted
1, Get if it has been recently viewed (Cookie)
2, Else just get the last Inserted.
Pretty basic but the code has a serious "code smell" (repetition). In an ideal world I'd like to remove the conditional.
public Campaign GetDefaultCampaign()
{
Campaign campaign = null;
using (UserRepository userRepo = new UserRepository())
{
var user = userRepo.GetLoggedInUser();
if (user != null)
{
string campaignViewMode = "";
if (HttpContext.Current.Request.Cookies["CampaignViewMode"] != null)
{
campaignViewMode = HttpContext.Current.Request.Cookies["CampaignViewMode"].Value.ToString();
}
//Get Last worked on/viewed
campaign = _context.tbl_Campaign
.Where(x => x.Name == campaignViewMode & x.tbl_UserToCampaign
.Where(z => z.UserId == user.UserId & z.CampaignId == x.CampaignId)
.Select(u => u.UserId)
.FirstOrDefault() == user.UserId)
.Select(y => new Campaign()
{
CampaignId = y.CampaignId,
Name = y.Name,
WebName = y.WebName,
DateAdded = y.DateAdded
}).FirstOrDefault();
//Or get last inserted
if (campaign == null)
{
campaign = _context.tbl_Campaign
.Where(x => x.Name == campaignViewMode & x.tbl_UserToCampaign
.Where(z => z.UserId == user.UserId & z.CampaignId == x.CampaignId)
.Select(u => u.UserId)
.OrderByDescending(d => d.DateAdded).FirstOrDefault() == user.UserId)
.Select(y => new Campaign()
{
CampaignId = y.CampaignId,
Name = y.Name,
WebName = y.WebName,
DateAdded = y.DateAdded
}).FirstOrDefault();
}
}
}
return campaign;
}
Could you kindly point me in the right direction of removing the conditional or at the very last reduce the "smell" ?
Fully appreciate your time!
Regards,
There's alot going on here. Here's what I'd do.
Don't new up instances (as you do with Repository). Code against abstracts (IRepository) which is provided by a DI container which is injected into the class constructor.
Remove the duplication that maps your data model to your returned model (Select(x=> new Campaign()). Extract this out as a method or a separate responsibility entirely.
Remove the huge nested if(user!=null). Check for this right up front and return if it is null.
Refactor the two fetching operations behind an interface (IGetCampaigns) and create two classes; one that fetches the latest inserted, and one that fetches the last viewed/worked on. Inject one into the other to form a decorator chain, wired up by your DI container.
Probably a lot to take in if you're unfamiliar with these concepts; happy to go through this offline if you'd like.

select from list which has same code

I have a problem in getting the values for the below.
I have a table called Retailers which contains Id,Description,Language and Code
I declared a list in my application which contains all the retailers list
var retailers = new List<Retailer>();
Now I need to add results of two retailers with same code so I am trying to do below and I am sure I am doing something wrong.
foreach (var retailer in retailers)
{
if (retailer.LanguageId != null)
{
// Here I am trying to findout if there are any other retailers who
// has same code if true then I need entire row of that retailer
**var retailerWithSameUacode = !retailers.Select(item => item.Code == retailerCode).SingleOrDefault();**
if (retailerWithSameUacode != null)
{
// Do something
}
}
}
Any help is much appreciated !
I don't think I entirely understand your question, but from your code comment and your attempt to select a retailer with the same code, I present to you the following..
To get the first retailer out of your list with a code that matches the current retailer, you would need to do this:
Retailer retailerWithMatchingCode = retailers.Where(r => r.Code == retailer.Code).FirstOrDefault();
You can then check the retailerWithMatchingCode object for a null value. If you just want to know if a retailer with a matching code exists, this is what you would do:
if (retailers.Any(r => r.Code == retailer.Code))
//Do something..
To get a list of retailers who have a matching "Code" property value, you would need to do this:
List<Retailer> retailersWithMatchingCode = retailers.Where(r => r.Code == retailer.Code).ToList();
Please note that this code is untested.
Try this solution:
var retailerWithSameUacode = retailers
.Where(item => item.LanguageId != null && item.Code == retailerCode)
.ToList();
foreach (var item in retailerWithSameUacode)
{
// Do something
}

Sorting data issue

So I have a little issue in sorting some data I have. In a Telerik Grid, I have a column called Requestor that displays the name of a person or Unit (group of people). The problem is, Requestor has two sources it can get it's data from. Here are the two sources.
1.) RequestorId: This is a foreign key to a table called Customer. Here, I store all the data for the user, including their full name. This field can be null btw.
2.) UnitId: This is another foreign key to a table called Units. Here, I store all the data for the Units, particularlly their names. This field can be null btw.
Here is the logic:
//Entity class that contains all the data for my grid
var purchaseOrders = _purchaseOrders.GetPurchaseOrders();
//Key is Id of PurchaseOrders, Value is name of requestor
var dictionary = new Dictionary<int, string>();
foreach (var purchaseOrder in purchaseOrders)
{
if (purchaseOrder.requestorId != null)
dictionary.add(purchaseOrder.Requestor.Fullname);
else
dictionary.add(purchaseOrder.unit.Fullname);
}
dictionary.orderby(x => x.value).ToDictionary(x => x.Key, x.Value);
var tempPurchaseOrders = new List<PurchaseOrder>();
foreach (var item in dictionary)
{
tempPurchaseOrders.Add(purchaseOrders.Where(x => x.Id == item.Key).FirstOrDefault());
}
purchaseOrders = tempPurchaseOrders.AsQueryable();
return purchaseOrders;
This logic returns an ordered list based on what I want to do, however, the problem is the amount of time it takes to process. It takes 1 minute to process. That's horrible obviously. Is there anyway to optimize this? I cut down the source after I return for the grid because there is no logical way to really cut it down beforehand.
Any help would be appreciated. Thanks.
Edit: I found out I no longer am required to use the RequestName field. That limits the data to two areas now. Still a minute to process though.
Did you try something like this:
return _purchaseOrders.GetPurchaseOrders().Select(i => new
{
OrderColumn = i.requestorId != null ? purchaseOrder.Requestor.Fullname : purchaseOrder.unit.Fullname,
// map other columns
})
.OrderBy(i => i.OrderColumn);
A bit like SÅ‚awomir Rosiek's solution (but entity framework won't accept that statement):
return _purchaseOrders.GetPurchaseOrders()
.OrderBy(o => o.unit.Fullname).ToList();
(since you don't use RequestName anymore).
Especially when GetPurchaseOrders() is an IQueryable from EF you delegate the sorting to the database engine because the sort expression becomes part of the SQL statement.
So I came up with my own solution. I first tried what both SÅ‚awomir Rosiek and Gert Arnold did. Unfortunately, like Gert mentioned, the first answer would not go through. The second one had similar issues.
In the end, I created a class to store the data from both Requestors and Units. It consisted of the following:
internal class RequestorData
{
public int entityId { get; set; }
public string Name { get; set; }
public bool isRequestorId { get; set; }
}
Next, I did the following.
//Entity class that contains all the data for my grid
var purchaseOrders = _purchaseOrders.GetPurchaseOrders();
var tempPurchaseOrders = new List<PurchaseOrder>();
var requestors = new List<RequestorData>();
var customers = purchaseOrders.Select(po => po.Requestor).Distinct().ToList();
var units = purchaseOrders.Select(po => po.Unit).Distinct().ToList();
foreach (var customer in customers)
{
if (customer != null)
requestors.Add(new RequestorData { entityId = customer.Id, Name = customer.FullName, isRequestorId = true });
}
foreach (var unit in units)
{
if (unit != null)
requestors.Add(new RequestorData { entityId = unit.Id, Name = unit.FullName, isRequestorId = false });
}
requestors = requestors.OrderBy(r => r.Name).ToList();
foreach (var requestor in requestors)
{
var id = requestor.entityId;
if (requestor.isRequestorId)
tempPurchaseOrders.AddRange(purchaseOrders.Where(po => po.RequestorId == id).ToList());
else
tempPurchaseOrders.AddRange(purchaseOrders.Where(po => po.UnitId == id).ToList());
}
purchaseOrders = tempPurchaseOrders.AsQueryable();
return purchaseOrders;
I ran this new rendition and have a 5-6 second time of wait. That's not perfect but much better than before. Thanks for all the help.

Categories

Resources