EF Duplicated Value - c#

Im getting angry with this error and cannot solve it.
Please, some Jedi master help me.
I'm trying to save trhee Entities: Region, Content and RegionalContent. Region is OK but Regional Content has to be associated with one Content and each Content may have Many RegionalContents(Translations). But I always get a DbUpdateException that has a UpdateException that has a SqlCeException that says something like:
*Impossible to insert a duplicated value with same index. Table name = XBLContents,Constraint name = PK_XBLContents_000000000000001C *
I'm debugging it for some days and could not find the error. Please, note that I'm still a little Padawan.
This is the code that saves the objects in they proper Tables:
Region region;
if (!db.Regions.Any(x => x.ID == Locale))
{
region = new Region { ID = Locale };
db.Regions.Add(region);
db.SaveChanges();
}
else
region = db.Regions.SingleOrDefault(x => x.ID == Locale);
for (int i = start; i < (start + 2); i++)
{
string guid = itens[i].Groups["guid"].Value;
Content c = new Content(guid);
if (!db.Contents.Any(x => x.GUID == guid))
{
c.Type = Type.ToString();
c.PopularInfo(Locale);
db.Contents.Add(c);
}
else
c = db.Contents.SingleOrDefault(x => x.GUID == c.GUID);
RegionalContent regionalcontent;
if (!db.RegionalInfos.Any(x => x.ContentId == guid && x.RegionId == Locale))
{
if (c.HTML == null)
c.PopularInfo(Locale);
regionalcontent = new RegionalContent(c, Locale);
regionalcontent.Region = region;
regionalcontent.Name = HttpUtility.HtmlDecode(itens[i].Groups["name"].Value);
db.RegionalInfos.Add(regionalcontent);
db.Contents.Add(c);
db.SaveChanges();
}
else
regionalcontent = db.RegionalInfos.SingleOrDefault(x => x.ContentId == guid && x.RegionId == Locale);
c.RegionalInfo.Clear();
regionalcontent.Region = region;
c.RegionalInfo.Add(regionalcontent);
Contents.Add(c);
}

You are calling SingleOrDefault when you know 1 already exists. Just use Single.
I would not call SaveChanges to the very end.
Are you sure the GUIDs are unique every time?

Related

Refactoring the C# function to reduce its cognitive complexity

I'm getting the following error from SonarCube: "Refactor this method to reduce its Cognitive Complexity from 28 to the 15 allowed".
Thing is, with this high Cognitive Complexity score, I am not sure how to drive it down to required 15. I have tried to move three if statements to different methods, but it has lowered the score by only 6 pts. How should I refactor given code in order to meet the requirement?
[HttpGet]
public IActionResult GetTileViewer(string productId = "", string edgeId = "", string sizeId = "", double? thickness = null)
{
if (string.IsNullOrWhiteSpace(productId))
{
return new ObjectResult(new { Error = "You need to specify a product id" })
{ StatusCode = (int)HttpStatusCode.InternalServerError };
}
var commerceService = new CommerceService();
var isImperial = commerceService.IsImperialMeasure();
var id = 0;
Guid guid;
RockstarProductTile product = null;
if (Guid.TryParse(productId, out guid))
{
product = ProductUtilities.GetProduct<RockstarProductTile>(guid);
}
else if (int.TryParse(productId, out id))
{
product = ProductUtilities.GetProduct<RockstarProductTile>(id);
}
if (product != null)
{
double? length = null;
double? width = null;
try
{
if (!string.IsNullOrWhiteSpace(sizeId))
{
var split = sizeId.Split('-');
length = double.Parse(split[0]);
width = double.Parse(split[1]);
}
var variants = product.Variants
.Where(x => string.IsNullOrWhiteSpace(edgeId) || commerceService.GetRelatedEntries(x, CommerceAssociationGroups.Edge)
.Where(y => y.ContentLink.ID.ToString() == edgeId || y.ContentGuid.ToString() == edgeId).Any());
if (isImperial)
{
variants = variants
.Where(x => length == null || x.Rockstar_RockstarProductTileVariant_TileLengthInches == length || x.Rockstar_RockstarProductTileVariant_TileLengthFeet == length)
.Where(x => width == null || x.Rockstar_RockstarProductTileVariant_TileWidthInches == width || x.Rockstar_RockstarProductTileVariant_TileWidthFeet == width)
.Where(x => thickness == null || x.Rockstar_RockstarProductTileVariant_TileThicknessInches == thickness || x.Rockstar_RockstarProductTileVariant_TileThicknessFeet == thickness);
}
else
{
variants = variants
.Where(x => length == null || x.Rockstar_RockstarProductTileVariant_TileLengthInches == length)
.Where(x => width == null || x.Rockstar_RockstarProductTileVariant_TileWidthInches == width)
.Where(x => thickness == null || x.Rockstar_RockstarProductTileVariant_TileThicknessInches == thickness);
}
var variant = variants.FirstOrDefault();
if (variant != null)
{
var tileViewer = commerceService.GetRelatedEntries(variant, CommerceAssociationGroups.TileViewer).FirstOrDefault() as RockstarTileViewer;
var images = tileViewer?.Rockstar_TileViewer_Images?.Items.Select(x => _urlUtilities.GetRelativeUrl(x.ContentLink)).ToList();
var tempId = 0;
Guid tempGuid;
RockstarProductEdge edge = null;
if (Guid.TryParse(edgeId, out tempGuid))
{
edge = ProductUtilities.GetProduct<RockstarProductEdge>(tempGuid);
}
else if (int.TryParse(edgeId, out tempId))
{
edge = ProductUtilities.GetProduct<RockstarProductEdge>(tempId);
}
if (images != null)
{
return new JsonResult(new TileViewerDataObject { Label = edge?.Rockstar_RockstarProductEdge_EdgeName?.SupAndSubOnly() ?? product.DisplayName, Images = images });
}
return new JsonResult(new TileViewerDataObject { Label = edge?.Rockstar_RockstarProductEdge_EdgeName?.SupAndSubOnly() ?? product.DisplayName });
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during get tile viewer: {Message}", ex.Message);
}
}
return new JsonResult(new TileViewerDataObject());
}
AFAIK among the largest contributors to the cognitive complexity are nested expressions, so try reduce nesting. For example invert if - from if (product != null) to:
if (product == null)
{
return new JsonResult(new TileViewerDataObject());
}
double? length = null; // also can be moved into the try block, not needed here
double? width = null;// also can be moved into the try block, not needed here
try
{
...
}
...
Then getting product should be moved to separate method (also for quite some time you can inline the variable declaration for out variables like id and guid) :
private RockstarProductTile GetProduct(string productId)
{
RockstarProductTile result = null;
if (Guid.TryParse(productId, out var guid))
{
product = ProductUtilities.GetProduct<RockstarProductTile>(guid);
}
else if (int.TryParse(productId, out var id))
{
product = ProductUtilities.GetProduct<RockstarProductTile>(id);
}
return result;
}
And in the method body just call it:
RockstarProductTile product = GetProduct(productId);
Then apply the same approaches to the try body (also possibly move to separate method) - try inverting at least some of the if's (if (variant != null) is a good candidate) and move getting edge by edgeId into separate method.
Also try to get methods to be less then one screen (by breaking down it in smaller ones, finding variant can be moved to separate function too).

Check if something exists in .net core database and return as boolean

So I'm trying to figure out how to check if something exists in my database. In this case what is happening is it's figuring out if the user has 'Liked' an image, and returning it as a true or false value. The way I'm doing it is to check if there is one version or more versions of this 'Like', if there is, return true, otherwise return false. This is the code.
What I'm currently doing:
public bool checkCurrentUserLiked(int currentUserId, int imageId)
{
var hasData = _context.PhotoLikes.Where(x => x.LikerId == currentUserId && x.ImageId == imageId);
var dataToReturn = false;
if (hasData.Count() >= 1)
{
// entity exists in database
dataToReturn = true;
}
else
{
dataToReturn = false;
// nope
}
return dataToReturn;
}
Another way that I tried
public bool checkCurrentUserLiked(int currentUserId, int imageId)
{
bool hasData = _context.PhotoLikes.Any(x => x.LikerId == currentUserId && x.ImageId == imageId);
var dataToReturn = false;
if (hasData)
{
// entity exists in database
dataToReturn = true;
}
else
{
dataToReturn = false;
// nope
}
return dataToReturn;
}
When i get to the :
if (hasData.Count() == 1), the error i get is:
A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
and it doesn't run
[EDIT]
The error I'm getting here is : Cannot implicitly convert type 'System.Linq.IQueryable' to 'bool'
public bool checkCurrentUserLiked(int currentUserId, int imageId)
{
_context.PhotoLikes.Any(x => x.LikerId == currentUserId && x.ImageId == imageId);
}
try this:
public bool checkCurrentUserLiked(int currentUserId, int imageId)
=> _context.PhotoLikes.Any(x => x.LikerId == currentUserId && x.ImageId == imageId));
I've tried all of the methods suggested but none of them worked, what I ended up doing was removing the function and rewriting it inside of the property that needed it.
This is what I mean:
'hasCurrentUserLiked' is what I was trying to work out. I didn't really make any major changes, I just changed the code around (not sure why this works, but it does)
(f, p) => new FeedsForReturnDto
{
Id = f.feed.Id,
PhotoUrl = f.feed.photoUrl,
Username = f.feed.Username,
Description = f.feed.Description,
DateAdded = f.feed.DateAdded,
IsImage = f.feed.IsImage,
// v Is the thing we were trying to figure out
hasCurrentUserLiked = _context.PhotoLikes.Any(x => x.LikerId == user.Id && x.ImageId == f.feed.Id),
Likes = _context.PhotoLikes.Where(x => x.ImageId == f.feed.Id).Count()
});

ASP.Net - Mvc5 : LINQ , Saving duplicate record problem

I am coding daily counter. Database Counter Table is empty. If someone is my first visitor of current day, then I am adding a record to database and i am setting counter=1; After this, when other visitor visit current day, then i am increasing my counter++ and i am updating the record.
So I my records must be like this:
Date:2018-10-01 counter:23
Date:2018-10-02 counter:65
Date:2018-10-03 counter:20
Date:2018-10-04 counter:89
My problem is this: If the site get visitor same time, linq save 2 record for same day. Like this:
Date:2018-10-01 counter:23
Date:2018-10-02 counter:1 //First record: counter=1
Date:2018-10-02 counter:65 //Second record: counter=65
Date:2018-10-03 counter:20
Date:2018-10-04 counter:1 //First record
Date:2018-10-04 counter:89 //second record
Date must be unique. How can I resolve this problem? My code is below. Thanks a lot.
public static int IncreaseCounter_DailySiteVisitors()
{
int counter = 0;
using (var context = new MyProjectEntities())
{
try
{
string format = "dd.MM.yyyy";
DateTime Today = DateTime.Now;
var obj = (from record in context.CounterDailySiteVisitor
where
record.DateRecord != null
&& record.DateRecord.HasValue
&& record.DateRecord.Value.Year == Today.Year
&& record.DateRecord.Value.Month == Today.Month
&& record.DateRecord.Value.Day == Today.Day
select record).FirstOrDefault();
//var obj = context.CounterDailyVisitor.Where(x => x.DateRecord != null && ((DateTime)x.DateRecord).ToString("yyyy.MM.dd") == DateTime.Now.ToString("yyyy.MM.dd")).FirstOrDefault();
if (obj != null)
{
counter = obj.Count ?? 0;
counter++;
obj.Count = counter;
context.SaveChanges();
}
else
{
var newRecordObj = context.CounterDailySiteVisitor.Create();
newRecordObj.Count = 1;
newRecordObj.DateRecord = Today;
context.CounterDailySiteVisitor.Add(newRecordObj);
context.SaveChanges();
}
}
catch (Exception e)
{
}
}
return counter;
}
the chances of this being hit by two thread at the same time is quite low.
but i guess technically it can so you would need to wrap this in a lock
Something like below...
public static int IncreaseCounter_DailySiteVisitors()
{
private readonly object somethingObject = new object();
var context = new MyProjectEntities()
var today = DateTime.Now;
var todaysRecord = context.CounterDailyVisitor
.SingleOrDefault(x => x.DateRecord.Year == Today.Year
&& x.DateRecord.Month == Today.Month
&& x.DateRecord.Day == Today.Day
);
if (todaysRecord != null)
{
//the existing count + 1
todaysRecord.Count = todaysRecord.Count++;
}
else
{
Lock(somethingObject)
{
//recheck
var todaysRecord = context.CounterDailyVisitor
.SingleOrDefault(x => x.DateRecord.Year == Today.Year
&& x.DateRecord.Month == Today.Month
&& x.DateRecord.Day == Today.Day
);
if (todaysRecord != null)
{
//the existing count + 1
todaysRecord.Count = todaysRecord.Count++;
}
else
{
var newRecordObj = new CounterDailyVisitor();
newRecordObj.Count = 1;
newRecordObj.DateRecord = DateTime.Now; //this shouldnt be nullable
context.CounterDailySiteVisitor.Add(newRecordObj);
}
}
}
context.SaveChanges();
}
This is quite a common concurrency problem i.e. race condition. You will either have to Lock around the code that reads and subsequently updates/inserts the value. Or you should call a stored procedure and have all the logic inside the stored proc.
Lock comes with it's own set of issues if you're planning on using a web farm or running multiple instances of this MVC app.

Update m-to-m relationship, duplicate primary key

i am trying to update a m-to-m relation with a ListBox. My entity-model looks like this:
I have a ListBox with Checkboxes where the user can decide which Player is in the league and which is not (IsSelected-Property). There are two problems: At first i can't check and then uncheck a Player (it won't be deleted). Second Problem: the first try, everything works and when i do the selection again, i get the following exception:
_innerException {"An error occurred while updating the entries. See the inner exception for details."} System.Exception {System.Data.Entity.Core.UpdateException}
_innerException {"Violation of PRIMARY KEY constraint 'PLID'. Cannot insert duplicate key in object 'dbo.PlayerLeague'. The duplicate key value is (2, 2).\r\nThe statement has been terminated."} System.Exception {System.Data.SqlClient.SqlException}
using (BettingLeagueEntities entities = new BettingLeagueEntities())
{
foreach (PlayerCheckBoxList p in this.PlayerList)
{
if(p.IsSelected == true)
{
PlayerLeague pl = new PlayerLeague();
pl.League = this.ActiveLeague;
pl.Player = p.ActivePlayer;
var local = entities.Set<Player>().Local.FirstOrDefault(x => x.PID == p.ActivePlayer.PID);
if(local != null)
{
entities.Entry(local).State = System.Data.Entity.EntityState.Detached;
}
var localLeague = entities.Set<League>().Local.FirstOrDefault(x => x.LID == this.ActiveLeague.LID);
if (localLeague != null)
{
entities.Entry(localLeague).State = System.Data.Entity.EntityState.Detached;
}
if (entities.Entry(p.ActivePlayer).State == System.Data.Entity.EntityState.Detached)
{
entities.Player.Add(p.ActivePlayer);
entities.Entry(p.ActivePlayer).State = System.Data.Entity.EntityState.Modified;
}
if (entities.Entry(this.ActiveLeague).State == System.Data.Entity.EntityState.Detached)
{
entities.League.Add(this.ActiveLeague);
entities.Entry(this.ActiveLeague).State = System.Data.Entity.EntityState.Modified;
}
if(p.ActivePlayer.PlayerLeague.All(x => x.LID != this.ActiveLeague.LID))
{
p.ActivePlayer.PlayerLeague.Add(pl);
this.ActiveLeague.PlayerLeague.Add(pl);
}
}
else
{
PlayerLeague local = entities.Set<PlayerLeague>().Local.FirstOrDefault(x => x.LID == this.ActiveLeague.LID && x.PID == p.ActivePlayer.PID);
if(local != null)
{
entities.PlayerLeague.Attach(local);
entities.PlayerLeague.Remove(local);
}
entities.SaveChanges();
}
}
entities.SaveChanges();
}
I have no clue how to solve this, do you have any suggestions?
I have it! I tried to comment a little bit to make it understandable.
The first problem was that i checked if my PlayerLeague already exists too lately. I moved this condition in my first if(statement).
The second error was, that in my else block, my statement to find a playerleague returned alsways null. Now i check if there is any entity and if this is true, i delete it.
using (BettingLeagueEntities entities = new BettingLeagueEntities())
{
foreach (PlayerCheckBoxList p in this.PlayerList)
{
// Check if the Player is seleceted and if the ActivePlayer has the Active League
if (p.IsSelected == true && p.ActivePlayer.PlayerLeague.All(x => x.LID != this.ActiveLeague.LID))
{
// Define the new PlayerLeague
PlayerLeague pl = new PlayerLeague {PID = p.ActivePlayer.PID, LID = this.ActiveLeague.LID};
var localPlayer = entities.Set<Player>().Local.FirstOrDefault(x => x.PID == p.ActivePlayer.PID);
if (localPlayer != null)
{
entities.Entry(localPlayer).State = System.Data.Entity.EntityState.Detached;
}
if (entities.Entry(p.ActivePlayer).State == System.Data.Entity.EntityState.Detached)
{
entities.Player.Add(p.ActivePlayer);
entities.Entry(p.ActivePlayer).State = System.Data.Entity.EntityState.Modified;
}
var localLeague = entities.Set<League>().Local.FirstOrDefault(x => x.LID == this.ActiveLeague.LID);
if (localLeague != null)
{
entities.Entry(localLeague).State = System.Data.Entity.EntityState.Detached;
}
if (entities.Entry(this.ActiveLeague).State == System.Data.Entity.EntityState.Detached)
{
entities.League.Add(this.ActiveLeague);
entities.Entry(this.ActiveLeague).State = System.Data.Entity.EntityState.Modified;
}
p.ActivePlayer.PlayerLeague.Add(pl);
this.ActiveLeague.PlayerLeague.Add(pl);
}
else
{
// Check if there is a PlayerLeague for this Player and league
bool hasPlayerLeague =
entities.PlayerLeague.Any(x => x.LID == this.ActiveLeague.LID && x.PID == p.ActivePlayer.PID);
if (hasPlayerLeague && p.IsSelected == false)
{
// Find PlayerLeague
PlayerLeague pl =
entities.PlayerLeague.FirstOrDefault(
x => x.LID == this.ActiveLeague.LID && x.PID == p.ActivePlayer.PID);
// Attach and Remove PlayerLeague
entities.PlayerLeague.Attach(pl);
entities.PlayerLeague.Remove(pl);
}
entities.SaveChanges();
}
}
}

update linq to sql values with select new keyword

How to update linq to sql values with select new keyword with anonymous types because I am using var keyword with select new query I need in in this but it returns an error like this
Compiler Error Message: CS0200: Property or indexer 'AnonymousType#1.Code' cannot be assigned to -- it is read only
This is my code:
var ProjectView12 = (from x in db.Projects
select new
{
add = db.Locations.Where(y = > y.ID == x.RegionID).FirstOrDefault().Name,
Province = db.Locations.Where(y = > y.ID == x.ProvinceID).FirstOrDefault().Name,
District = db.Locations.Where(y = > y.ID == x.DistrictID).FirstOrDefault().Name,
Code = x.Code,
Name = x.Name,
ProjectIdentificationDate = db.Milestones.Where(y = > y.ProjectID == x.ID && y.StageID == 1 && y.ComponentID == 1 && y.ModuleID == 1).FirstOrDefault().Date.ToString(),
ProjectLat = Convert.ToDecimal(x.Lat),
ProjectLong = Convert.ToDecimal(x.Lon),
Remarks = db.Milestones.Where(y = > y.ProjectID == x.ID && y.StageID == 1 && y.ComponentID == 1 && y.ModuleID == 1).FirstOrDefault().Remarks.ToString(),
}).ToList();
foreach(var item in ProjectView12)
{
item.Code = txtSubProjectCode.Text;
item.Name = txtSubProjectName.Text;
item.ProjectLat = Convert.ToDecimal(txtLatitude.Text);
item.ProjectLong = Convert.ToDecimal(txtLongitude.Text);
item.ProjectIdentificationDate = txtDate.Text;
item.Remarks = txtRemarks.Text;
} // txtLocation.Text = item.Region + ">" + item.Province + ">" + item.District;
try
{
db.SubmitChanges();
}
catch (Exception ex)
{
throw ex;
}
Well, you're getting the compiler error because - as it says - the properties of anonymous types are read-only in C#.
More fundamentally, even if you could modify them, you'd have to expect LINQ to SQL to reverse whatever you put into your projection in order to update the original tables. That seems a fairly tall order to me - particularly for the Remarks property in this particular case.
Basically, in order to update the database, you need to make changes to the entities that are mapped from your tables. Make your query select the relevant entities, then you can project from those later on in client-side code, if necessary - so long as you've still got a reference to the entity to modify.

Categories