Soft deletion in mvc - asp.net-mvc

I want to soft delete, no records are physically deleted from the database, just sets the IsDeleted filed to true.It would be more than one data with that value. In controller I add:
var res = (from c in db.Books
where c.IsDeleted == 1
select c);
And I don't know how to add a condition to a if clause. Tried
if (res != 1){
return View(db.Books.ToList());
}
but it isn't. Has anyone have an idea what to do?

== checks for equality. if you want to set the IsDeleted field, you need something slightly different
try something like
var res = (from c in db.Books
where c.Id == IdToFind).SingleOrDefault().IsDeleted = 1;
Disclaimer: Code may not be accurate, but should give ou an idea!

Related

Linq query to check for two values

I'm new to using linq to query the database and just wonder if my query has any flaws, because it does not act as I want. I just wnat to check if there excist any items in the database that match two numbers.
If yes, nothing should be added to the database, but it seems like it continue to add new stuff despite I make a check if an item already excist with this numbers! What have i done wrong and how can I improve my query?
if(db.Member.Any(x => x.ID == c && x.CountryID == d))
{
Do something if there is a match and the member already excist in DB...
} else
{
Write new Member to DB....
}
Please try this version too.
var memberObject=db.Member.Where(x => x.ID == c && x.CountryID == d).FirstOrDefault();
if (memberObject==null){
//Write new Member to DB....
}else{
//Do something if there is a match and the member already excist in DB...
}

LINQ query with omitted user input

so I have a form with several fields which are criteria for searching in a database.
I want to formulate a query using LINQ like so:
var Coll = (from obj in table where value1 = criteria1 && value2 = criteria2...)
and so on.
My problem is, I don't want to write it using If statements to check if every field has been filled in, nor do I want to make separate methods for the various search cases (criteria 1 and criteria 5 input; criteria 2 and criteria 3 input ... etc.)
So my question is: How can I achieve this without writing an excessive amount of code? If I just write in the query with comparison, will it screw up the return values if the user inputs only SOME values?
Thanks for your help.
Yes, it will screw up.
I would go with the ifs, I don't see what's wrong with them:
var query = table;
if(criteria1 != null)
query = query.Where(x => x.Value1 == criteria1);
if(criteria2 != null)
query = query.Where(x => x.Value2 == criteria2);
If you have a lot of criteria you could use expressions, a dictionary and a loop to cut down on the repetitive code.
In an ASP.NET MVC app, chances are your user input is coming from a form which is being POSTed to your server. In that case, you can make use of strongly-typed views, using a viewmodel with [Required] on the criteria that MUST be provided. Then you wrap your method in if (ModelState.IsValid) { ... } and you've excluded all the cases where the user hasn't given you something they need.
Beyond that, if you can collect your criteria into a list, you can filter it. So, you could do something like this:
filterBy = userValues.Where(v => v != null);
var Coll = (from obj in table where filterBy.Contains(value1) select obj);
You can make this more complex by having a Dictionary (or Lookup for non-unique keys) that contains a user-entered value along with some label (an enum, perhaps) that tells you which field they're filtering by, and then you can group them by that label to separate out the filters for each field, and then filter as above. You could even have a custom SearchFilter object that contains other info, so you can have filters with AND, NOT and OR conditions...
Failing that, you can remember that until you trigger evaluation of an IQueryable, it doesn't hit the database, so you can just do this:
var Coll = (from obj in table where value1 == requiredCriteria select obj);
if(criteria1 != null)
{
query = query.Where(x => x.Value1 == criteria1);
}
//etc...
if(criteria5 != null)
{
query = query.Where(x => x.Value5 == criteria5);
}
return query.ToList();
That first line applies any criteria that MUST be there; if there aren't any mandatory ones then it could just be var Coll = table;.
That will add any criteria that are provided will be applied, any that aren't will be ignored, you catch all the possible combinations, and only one query is made at the end when you .ToList() it.
As I understand of your question you want to centralize multiple if for the sake of readability; if I were right the following would be one of some possible solutions
Func<object, object, bool> CheckValueWithAnd = (x, y) => x == null ? true : x==y;
var query = from obj in table
where CheckValue(obj.value1, criteria1) &&
CheckValue(obj.value2, criteria2) &&
...
select obj;
It ls flexible because in different situations or scenarios you can change the function in the way that fulfill your expectation and you do not need to have multiple if.
If you want to use OR operand in your expression you need to have second function
Func<object, object, bool> CheckValueWithOr = (x, y) => x == null ? false : x==y;

How to specify a condition in an Entity Framework join?

I have a Blogs table related to BlogComments table with a FK.
I need to get, through Linq, all the BlogComments items that match a certain flag
If i do:
db.Blogs.Where(b => b.BlogComments.Where(bc=>bc.Where(bc.Flag1==true));
I get "Cannot implicity convert type IEnumerable to bool"
Which is the best way to solve this problem?
Because this expression:
b.BlogComments.Where(...)
returns an IEnumerable (of BlogComments), but you are then passing it into this method:
db.Blogs.Where(...)
which expects a function that returns a bool, not an IEnumerable.
You probably need something like this:
var blogId = 5;
db.BlogComments.Where(bc => bc.BlogId == blogId && bc.Flag1 == true)
If you need to select comments from multiple blogs, then you could try using Contains:
var blogIds = new [] {1,2,3,4,5};
db.BlogComments.Where(bc => blogIds.Contains(bc.BlogId) && bc.Flag1 == true)
If you want to place criteria on the set of blogs, as well as the comments, then you could do this in one query using a join:
var query = from b in db.Blogs
join c in db.BlogComments on c.Blog equals b
where b.SomeField == "some value"
&& c.Flag1 == true
select c;
You could write it in LINQ form.
var blogs = from b in db.Blogs
join c in db.BlogComments
on b.BlogId equals c.BlogId
where c.Flag1
select b;
If you have a composite key you can write
on new { A = b.BlogKey1, B = b.BlogKey2 }
equals new { A = c.CommentKey1, B = c.CommentKey2 }
If it were me, I would just have another DbSet in your DbContext.
DbSet<BlogComment> BlogComments
and just search through there without going through Blogs.
db.BlogComments.Where(bc => bc.Flag1 == true);
If anyone knows if there's anything wrong in doing so, then I'm all ears :)

adding a record to a LINQ object (concat) taking values from another

Hi i'm looking for some help in how to append rows to an existing LINQ object. In the controller method below I have two result sets, i'm looping the Sites and want to add a record to the 'results' object for each record in the Sites object.
I've tried concat etc but not getting anywhere, just need s small example to assist, many thanks in advance, J
public IQueryable<UsersToSite> FindAllUsersToSites(int userId,SystemType obj)
{
var results = (from usersToSite in this._db.UsersToSites
where usersToSite.UserId == userId &&
usersToSite.SystemTypeId == obj
orderby usersToSite.Site.SiteDescription
select usersToSite);
// Now for each remaining Site append a record thats not physically in the database. From the view the user will be able to click these records to ADD new
// I'll then build in a search
var sites = (from site in this._db.Sites
where !(from o in _db.UsersToSites where (o.UserId == userId && o.SystemTypeId == obj) select o.SiteId).Contains(site.SiteId)
orderby site.SiteDescription
select site);
foreach (var site in sites)
{
// HERE I want to create the new ROW in results object
//results = new[results] { new { UsersToSiteId = null, AccessTypeId = null } }.Concat(sites);
//SiteId=site.SiteId,
//UsersToSiteId = 0,
//AccessTypeId = 0,
//UserId = userId
}
return results;
}
I don't think you can, if you want to have keep queryable.
However, if you materialize the results with ToList(), then you can:
var sites = (from site in this._db.Sites
where !(from o in _db.UsersToSites where (o.UserId == userId && o.SystemTypeId == obj) select o.SiteId).Contains(site.SiteId)
orderby site.SiteDescription
select site)
.ToList();
sites.Add(new Site { UsersToSiteId = null, etc });
If it was LINQ to Objects, you could do Concat.
The problem here that it can't do ConcatLINQ query that will have one part from SQL and another from objects. You need to materialize results first and then concat to object.

LINQ Query to Produce Non-Empty Nested Menu?

To see my problem in action, visit www.apoads.com and hover over the "Local Businesses" menu item. It's a series of nested unordered lists generated from a db call. Go ahead and click on a few of the items underneath "Local Businesses", you'll see that most of the categories are empty (the site is very new).
Problem:
I only want to show the categories that actually contain a local business. Here's what my category schema looks like:
int BizCatID - PK,Identity (used in FK relation to the table named Biz)
int? ParentID - BizCatID of this rows parentID, null means no parent
nvarchar Name - name of the category
nvarchar Caption - quick description of the category
What I've tried:
I've tried to update my LINQ query like so:
from c in db.BizCategories where c.ParentID != null && c.Bizs.Count() > 0 select c;
That obviously won't work, cause I'll need the parent category to show if the child category contains a business. So I tried this:
from c in db.BizCategories where c.Bizs.Count() > 0 select c;
This doesn't work either, as parent categories will never have any businesses under them. So it seems like I'll need to do some sort of inverse recursion, but I'm not sure how to do that.
Or, perhaps I'm making things to hard for myself and I need to change my db schemas?
create classes to hold your information like so
public class BusinessCat
{
public string Name{get;set;}
public string Caption{get;set;}
public List<'dunno datatype'> Children{get;set;};
}
var results = from c in BizCategories
where c.ParentID == null
select new BusinessCat{
Name = c.Name,
Caption = c.Caption,
Children = (from d in BizCategories
where d.ParentID == c.BizCatID && d.Bizs.Count() > 0 select d).ToList()
}
and with this you have a list full of Children and you can simply iterate through it with a foreach.
You can also do .Join() extension method for
where d.ParentID == c.BizCatID && d.Bizs.Count()
I'm not sure about the recursion bit but this might get you started. Is a two-level query.
I'm guessing you want to support any number of levels.
var allcats = (from c in db. BizCategories
select c).ToList(); // This will retrieve them all from the database.
var twoLevels = from c in allcats
where c.ParentID == null
select new {
Name = c.Name, Caption = c.Caption,
Children =
from d in allcats
where d.ParentID == c.BizCatID
select d
};
A query like this is getting close to what I need:
from c in BizCategories
where c.ParentID == null
select new {
Name = c.Name, Caption = c.Caption,
Children =
from d in BizCategories
where d.ParentID == c.BizCatID && d.Bizs.Count() > 0
select d
}
I should be able run another LINQ query over these results and pull out exactly what I need. Not at a computer where I can test that now, but will reply once I can. Thanks!

Resources