C#: How to see if a Linq2SQL entity is in the database - c#

I would like to check if an entity is already added to the database. So, how can I see this difference between a and b?
var a = dataContext.Things.First(x => x.Name == something);
var b = new Thing { Name = something };
To make it clearer, if I have this:
var thing = dataContext.Things.FirstOrDefault(x => x.Name == something)
?? new Thing { Name = something };
How can I see if thing needs to be inserted?

If you use FirstOrDefault instead of First, that will return null if there are no matches.
As for knowing whether you need to insert - just remember whether or not it was null to start with:
var a = dataContext.Things.FirstOrDefault(x => x.Name == something);
bool needsInsertion = (a == null);
a = a ?? new Thing { Name = something };
Alternatively, if there's an ID field in Thing which is automatically populated by the database, you can just use that to detect whether it's already in the database or not.

Related

How to insert old record to new entity?

I am trying to check record , if exists declare to data with old one . But if doesnt then create a new one. Here is my code ;
var teamCheck= FootballerDBContext.Teams.Any(r => r.Name == teamName.Text.Trim());
if (teamCheck)
{
team = FootballerDBContext.Teams.FirstOrDefault(c => c.Name == teamName.Text);
}
FootballerDBContext.Teams.Add(team);
FootballerDBContext.SaveChanges(); // throwing exception right there . I did it exactly same to other entity everything was fine.
Here is other entity , i did the same but Team throws exception. No errors here , doing what i want. It doesnt create new entity with new ID , just declaring old one.
( sponsor has many-to-many relationship , team has one-to-many )
var sponsorCheck = FootballerDBContext.Sponsors.Any(x => x.Name == Sponsor.Text.Trim());
if (sponsorCheck)
{
sponsor = FootballerDBContext.Sponsors.FirstOrDefault(z => z.Name == Sponsor.Text);
}
FootballerDBContext.FootballerSponsor.Add(fbsp);
FootballerDBContext.SaveChanges();
Don't do it like you're doing; it queries the database twice
Do a pattern like this instead:
var team = FootballerDBContext.Teams.FirstOrDefault(c => c.Name == teamName.Text.Trim());
if(team == default) //or null
{
team = new Team(){ Name = teamName.Text };
FootballerDBContext.Teams.Add(team);
}
team.Location = teamLocation.Text;
...
FootballerDBContext.SaveChanges();
Query using Find or FirstOrDefault
If the result is null make a new one and assign it to the variable that is null
Add the team to the context if you just made a new one
Now you definitely have a team, either because you made it new or because it already exists and is looked up
You can set other properties
Call save changes at the end and an update or insert command will be run as appropriate
These LINQ queries are not the same:
teamName.Text.Trim() vs teamName.Text
.Trim()
try to check if variable is null or not like this:
string teamName = teamName.Text.Trim()
if (!String.IsNullOrEmpty(teamName))
first: **team** default value is (teamName)
second: validate linq query... r => r.Name == teamName
if (second == false)
save first.

How can I append mutliple results from context to one list/variable LINQ C#

I'm working on small app for fetching products/articles, and I wrote a method that's getting articles by type. (types are contained in request arg).
What I'm trying to achieve is: append all results (from all if conditions if they are satisfied) to one main list which should be returned to customer..
When I'm debugging and checking query it says its returning type is IQueryable<Article> so basically my question is how can I append multiple IQueryables into one which should be returned to user..
This code below is not working because result is always empty..
I've tried also with var result = new List<Article>(); and later result.AddRange(query); and I've changed also return type to
return await result.AsQueryable().ToListAsync(); but obviously something breaks somewhere and I get an empty array at the end.
public async Task<IEnumerable<Article>> GetArticlesByType(ArticleObject request)
{
var result = new Article[] { }.AsQueryable();
IQueryable<ArticleDTO> query = null;
if (request.Food.HasValue && (bool)request.Food)
{
// Return type of query is IQueryable<Article>
query = _context.Articles.Where(x => x.Active == true && x.ArticleType == ArticleType.Food).Select(x => new Article
{
Id = x.Id,
ArticleName = x.ArticleName
});
// Here I just wanted if this condition is satisfied to add values to my result
result.AsQueryable().Union(query);
}
if (request.Drink.HasValue && (bool)request.Drink)
{
query = _context.Articles.Where(x => x.Active == true && x.ArticleType == ArticleType.Drink).Select(x => new Article
{
Id = x.Id,
ArticleName = x.ArticleName
});
// Again if there are any values in query add them to existing result values
result.AsQueryable().Union(query);
}
if (request.Candy.HasValue && (bool)request.Candy)
{
// When its candy I want also articles from food category
query = _context.Articles.Where(x => x.Active == true && x.ArticleType == ArticleType.Food || x.ArticleType == ArticleType.Candy).Select(x => new Article
{
Id = x.Id,
ArticleName = x.ArticleName
});
// Again if there are values in query add them to existing result
result.AsQueryable().Union(query);
}
//At the end return result and all the values in case all conditions were satisfied
return await result.ToListAsync();
}
Try with result.AsQueryable().Union(query.ToList());. This will fetch the object from database. So far query contains references to objects in database and not in your memory

Access list items by name to assign to variables

I am sure the answer to this is everywhere but I am struggling to find it, perhaps I am not wording it correctly?
I have a list of items as shown:
What I want to then do is something like:
var phoneNo = res("phone_number").Value;
But what is the actual syntax?
EDIT:
Here's something I've tried to no success:
Looks like you are trying to get value from your claims. You can do so as below:
var userClaims = context.HttpContext.User as ClaimsPrincipal;
Get you claim value:
if (userClaims.Claims.Where(x => x.Type == "phone_number").FirstOrDefault() != null)
{
var phoneNumberClaim = User.Claims.Where(x => x.Type == "phone_number").FirstOrDefault().Value;
}
There is a special structure in programming for such tasks. It is called Dictionary.
I think your ToClaims method should return Dictionary, so you can access values by whatever key you want. Also you can cast your list using .ToDictionary(...), where you could split string by ":" for key and value.
From the feedback given I would like to show two of the best methods I took away from this.
The method I went with:
//set up a dictionary
var claims = ctx.User.ToClaims().ToDictionary(claim => claim.Type, claim => claim.Value);
//access as follows
var phoneNo = claims["phone_number"];
var firstName = claims["given_name"];
//etc.
Another good way:
//set up IEnumerable
var claims = ctx.User.ToClaims();
//access as follows
var phoneNos = claims.FirstOrDefault(c => c.Type == "phone_number")?.Value;
var firstName = claims.FirstOrDefault(c => c.Type == "given_name")?.Value;
//etc.

Non-static method requires a target when checking paramater for null values

In the below code, if i uncomment the line starting with queItem.RequestedMap == null I get
Non-static method requires a target.
If I then instead rewrite it as it is now, with a .ToList() and then doing the same where query after that it works. This tells me that .net is not able to translate the null check of queItem.RequestedMap == null into something sql specific.
queItem is an object paramater passed to the method containing this code.
Is there a way I can write this without retrieving the data back to .net and then doing another where? The existing answers I found just said to remove such expressions from the lambda query, which I dont want to do.
var gameToJoin = db.Games
//.Where(x =>
// (queItem.RequestedMap == null || x.Map.Id == queItem.RequestedMap.Id) // no map preference or same map
//)
.ToList()
.Where(x =>
queItem.RequestedMap == null
|| x.Map.Id == queItem.RequestedMap.Id) // no map preference or same map)
.FirstOrDefault();
Edit: Also, in the real query expression there are multiple other expressions in the first .Where that is commented here, they always need to be checked.
var gameToJoin = db.Games.AsQueryable();
// add the where's that always need to be checked.
if (queItem.RequestMap != null)
{
gameToJoin = gameToJoin.Where(x => x.Map.Id = queItem.RequestMap.Id);
}
var result = gameToJoin.ToList();
Or if you'd rather use FirstOrDefault()
var gameToJoin = db.Games.AsQueryable();
// add the where's that always need to be checked.
if (queItem.RequestMap != null)
{
var result = new List<Game>();
var game = gameToJoin.FirstOrDefault(x => x.Map.Id = queItem.RequestMap.Id);
if (game != null)
{
result.Add(game);
}
return result;
}
return gameToJoin.ToList();
Wouldn't this produce what you want? I don't see a reason that queItem.RequestedMap check should be a part the LINQ, because it is not a part the database.
Game gameToJoin = null;
if(queItem.RequestedMap == null)
{
gameToJoin = db.Games
.Where(x => x.Map.Id == queItem.RequestedMap.Id)
.FirstOrDefault;
}

Matching objects by property name and value using Linq

I need to be able to match an object to a record by matching property names and values using a single Linq query. I don't see why this shouldn't be possible, but I haven't been able to figure out how to make this work. Right now I can do it using a loop but this is slow.
Heres the scenario:
I have tables set up that store records of any given entity by putting their primary keys into an associated table with the key's property name and value.
If I have a random object at run-time, I need to be able to check if a copy of that object exists in the database by checking if the object has property names that match all of the keys of a record in the database ( this would mean that they would be the same type of object) and then checking if the values for each of the keys match, giving me the same record.
Here's how I got it to work using a loop (simplified a bit):
public IQueryable<ResultDataType> MatchingRecordFor(object entity)
{
var result = Enumerable.Empty<ResultDataType>();
var records = _context.DataBaseRecords
var entityType = entity.GetType();
var properties = entityType.GetProperties().Where(p => p.PropertyType.Namespace == "System");
foreach (var property in properties)
{
var name = property.Name;
var value = property.GetValue(entity);
if (value != null)
{
var matchingRecords = records.Where(c => c.DataBaseRecordKeys.Any(k => k.DataBaseRecordKeyName == name && k.DataBaseRecordValue == value.ToString()));
if (matchingRecords.Count() > 0)
{
records = matchingRecords;
}
}
}
result = (from c in records
from p in c.DataBaseRecordProperties
select new ResultDataType()
{
ResultDataTypeId = c.ResultDataTypeID,
SubmitDate = c.SubmitDate,
SubmitUserId = c.SubmitUserId,
PropertyName = p.PropertyName
});
return result.AsQueryable();
}
The last statement joins a property table related to the database record with information on all of the properties.
This works well enough for a single record, but I'd like to get rid of that loop so that I can speed things up enough to work on many records.
using System.Reflection;
public IQueryable<ResultDataType> MatchingRecordFor(object entity)
{
var records = _context.DataBaseRecords;
var entityType = entity.GetType();
var properties = entityType.GetProperties().Where(p => p.PropertyType.Namespace == "System");
Func<KeyType, PropertyInfo, bool> keyMatchesProperty =
(k, p) => p.Name == k.DataBaseRecordKeyName && p.GetValue(entity).ToString() == k.DataBaseRecordValue;
var result =
from r in records
where r.DataBaseRecordKeys.All(k => properties.Any(pr => keyMatchesProperty(k, pr)))
from p in r.DataBaseRecordProperties
select new ResultDataType()
{
ResultDataTypeId = r.ResultDataTypeId,
SubmitDate = r.SubmitDate,
SubmitUserId = r.SubmitUserId,
PropertyName = p.PropertyName
});
return result.AsQueryable();
}
Hopefully I got that query language right. You'll have to benchmark it to see if it's more efficient than your original approach.
edit: This is wrong, see comments

Categories