Help needed using Predicate in Generics - c#-2.0

Presently i use a method which returns me the ICommand object based on the string comparisons got from the supplied key.
public ICommand getCommand(string mCommand)
{
foreach (object obj in objCommandList)
{
ICommand command = (ICommand)obj;
if (command.m_strCommandName == mCommand)
{
return command;
}
}
return null;
}
where objCommandList contains ICommand objects.
Now I want to improve my code or rather try an alternative to search amongst the collection i.e using an option such as Predicate delegate in retrieving the filtered object amongst the collection.
ie.
objCommandList.Find(Predicate syntax which is needed here...)
Can anyone help me with this.

You might try something like this:
objCommandList.Find(delegate(Icommand command) { return command.m_strCommandName == mCommand; });
or
objCommandList.Find(c => c.m_strCommandName == mCommand);

Related

Entity Framework Core 7 apply custom ValueConverter to Inserts and Updates

I am struggling to understand how to apply a custom ValueConverter to all the properties of all the models before every insert and update.
According to this resource it can be done:
https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions?tabs=data-annotations
"Value converters allow property values to be converted when reading from or **writing ** to the database"
I was able to accomplish this, but only when reading from the database, overriding ConfigureConventions in the Context:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Properties<string>().HaveConversion<ToUpperConverter>();
}
Converter
public class ToUpperConverter : ValueConverter<string, string>
{
public ToUpperConverter() : base(v => v, v => v.Trim().ToUpper())
{
}
}
Tried also to override the method SaveChangesAsync in the Context, this works but obviously I don't want to go manually for every property and for every model considering they can change at every time.
Using reflection here can be an option, but I am not really a big fan of it.
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
foreach (var entry in ChangeTracker.Entries<Player>())
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
entry.Entity.Name = entry.Entity.Name.ToUpper();
entry.Entity.MiddleName = entry.Entity.MiddleName?.ToUpper();
entry.Entity.Surname = entry.Entity.Surname.ToUpper();
}
}
return await base.SaveChangesAsync(cancellationToken);
}
Solved, after spending on this an entire day..
The first argument of the converter is the conversion happening to the database, the second argument is the conversion happening from the database.
public class ToUpperConverter : ValueConverter<string, string>
{
public ToUpperConverter() : base(
// writing to the database
v => v.Trim().ToUpper(),
// reading from the database
v => v.Trim().ToUpper())
{
}
}
Source: https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.metadata.builders.propertiesconfigurationbuilder.haveconversion?view=efcore-6.0
"The type to convert to and from or a type that inherits from ValueConverter."

Multiple searching in Asp.net (entity framework) with multiple search boxes

ImageI'm having a problem to develop a form that can be search by multiple search boxes.....when i'm trying to search name and email together ActionResult...compiler says both linq queries cannot be applied with && operator..i don.t know why...
[HttpPost]
public ActionResult Login(string search,string search2)
{
var obj = db.Emps.Where(x => x.Employee_name.StartsWith(search)) && db.Emps.Where(x=>x.Employee_email.StartsWith(search2));
return View(obj);
}
You need to use both conditions inside single Where
[HttpPost]
public ActionResult Login(string search,string search2)
{
var obj = db.Emps.Where(x => x.Employee_name.StartsWith(search) && x.Employee_email.StartsWith(search2));
return View(obj);
}
If you look at your current code, the first part db.Emps.Where(x => x.Employee_name.StartsWith(search)) is going to return a collection, IQueryable<Emp>
and the second part of the expression will also return the same type, IQueryable<Emp>.
So your code is basically trying to execute/compile the expression IQueryable<Emp> && IQueryable<Emp> and since it is not valid, the compiler is telling you that it is not valid.
Ideally, you should have both of your WHERE condition predicates inside the same Where method.
var obj = db.Emps.Where(x => x.Employee_name.StartsWith(search)
&& x.Employee_email.StartsWith(search2));
Keep in mind that, the variable obj is still of type IQueryable<Emp>. If you want to execute your LINQ query, you may call the ToList() method.
List<Emp> = db.Emps.Where(x => x.Employee_name.StartsWith(search)
&& x.Employee_email.StartsWith(search2)).ToList();
If you make the above change, make sure your view is strongly typed to List<Emp> instead of IQueryable

How to improve my Entity Framework , to join several database queries into single query

I have the following ActionFilter class, to implement my custom authorization system:-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CheckUserPermissionsAttribute : ActionFilterAttribute
{
Repository repository = new Repository();
public string Model { get; set; }
public string Action { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string ADusername = filterContext.HttpContext.User.Identity.Name.Substring(filterContext.HttpContext.User.Identity.Name.IndexOf("\\") + 1);
if (!repository.can(ADusername,Model,Action))
{
filterContext.Result = new HttpUnauthorizedResult("You cannot access this page");
}
base.OnActionExecuting(filterContext);
}
}
The above class will call the following repository method:-
public bool can(string user, string Model, string Action)
{
bool result;
bool result2;
int size =tms.PermisionLevels.Where(a5 => a5.Name == Action).SingleOrDefault().PermisionSize;
var securityrole = tms.SecurityroleTypePermisions.Where(a => a.PermisionLevel.PermisionSize >= size && a.TechnologyType.Name == Model).Select(a => a.SecurityRole).Include(w=>w.Groups).Include(w2=>w2.SecurityRoleUsers).ToList();
foreach (var item in securityrole)
{
result = item.SecurityRoleUsers.Any(a => a.UserName.ToLower() == user.ToLower());
var no = item.Groups.Select(a=>a.TMSUserGroups.Where(a2=>a2.UserName.ToLower() == user.ToLower()));
result2 = no.Count() == 1;
if (result || result2) {
return true;
}}
return false;
}
But inside my repository method , I am doing the following:-
Query the database and include all the Groups & SecurityRoleUsers when executing the .tolist()
Then filter the returned records insdie the server, based on the foreach loop.
But this will cause the following drawbacks:-
If I have many Groups and SecurityRoleUsers, then I will be getting them all from the DB, and then filter the result on the server.
And since this code will be executed whenever an action method is called, as it Is a security attribute at the begging of the controller class. So this might not be very efficient.
So my question is whether I can join all the queries inside the repository method to be single query , and do all the work on the Database and just return true or false to the server ?
The associated tables looks as follow:-
Ideally remove this foreach.
Try riding with Linq to Sql.
You should be more comfortable because it resembles SQL.
This link has several examples.
http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
Att
Julio Spader
wessolucoes.com.br
Use linq.
Ideally you should only have one line of code after you got the size value. e.g.
int size =tms.PermisionLevels.Where(a5 => a5.Name == Action).SingleOrDefault().PermisionSize;
var result = //One line of code to determine user authenticity
return result;
I think you should design you database in the way that join queries are easy to do. So you don't have to perform more than one select.
Try code-first EF, which links tables very easily.
You need to take care with Lazy Loading. If not used correctly, it will make a query to the database each object segmentation, especially in your foreach. With that already has a good improvement.
Take a look at this article. I think it will help you too.
http://www.sql-server-performance.com/2012/entity-framework-performance-optimization/
Att
Julio Spader
wessolucoes.com.br

Iterating over an unknown IQueryable's properties?

Forgive me if this has been asked before; I couldn't find anything close after a few searches:
I'm trying to write an ActionFilter in MVC that will "intercept" an IQueryable and nullify all the parent-child relationships at runtime. I'm doing this because Linq does not serialize objects properly if they have parent-child relationships (it throws a circular reference error because the parent refers to the child, which refers back to the parent and so on), and I need the object serialized to Json for an Ajax call. I have tried marking the child relationship in the DBML file with a privacy status of internal, and while this fixes the serialization problem, it also hides the child members from the view engine when the page renders, causing another error to be thrown. So, by fixing one problem, I cause another.
The only thing that fixes both problems is to manually set the child members to null just before returning the serialization, but I'm trying to avoid doing that because it's cumbersome, not reusable, etc. I'd rather use an ActionFilter to inspect the IQueryable that is being serialized and nullify any members with a Type of EntitySet (how Foreign Keys/Associations are represented). However, I don't have much experience with Reflection and can't find any examples that illustrate how to do something like this. So... is this possible with Reflection? Is there a better way to accomplish the same thing? I'll post the relevant code tomorrow when I'm back at my work computer.
Thanks,
Daniel
As promised, the code:
[GridAction]
public ActionResult _GetGrid()
{
IQueryable<Form> result = formRepository.GetAll();
foreach (Form f in result)
{
f.LineItems = null;
f.Notes = null;
}
return View(new GridModel<Form> { Data = result });
}
An added wrinkle is that I'm using the new Telerik MVC Extensions, so I'm not actually serializing the Json myself -- I'm just returning the IQueryable in an IGridModel, and the action filter [GridAction] does the rest.
So, just in case anyone's curious, here's how I finally solved this problem: I modified Damien Guard's T4 template to include the attribute [ScriptIgnore] above entities of type Association. This lets the JSON serializer know to not bother serializing these, thus preventing the circular reference problem I was getting. The generated code ends up looking like this:
private EntitySet<LineItem> _LineItems;
[ScriptIgnore]
[Association(Name=#"Form_LineItem", Storage=#"_LineItems", ThisKey=#"Id", OtherKey=#"FormId")]
public EntitySet<LineItem> LineItems
{
get {
return _LineItems;
}
set {
_LineItems.Assign(value);
}
}
This fixes the serialization problem I was having without disabling the use of child tables through LINQ. The grid action on the controller ends up looking like this:
[GridAction]
public ActionResult _GetGrid()
{
return View(new GridModel<Form> { Data = formRepository.GetAll() });
}
There are two options, one is to ignore those properties during serialization using [XmlIgnore]. The other one is to nullify the properties using reflection.
Ignore in serialization, simple usage sample that shows how to use default value in serialization:
[Serializable]
public class MyClass
{
[XmlIgnore]
public int IgnoredVal { get; set; }
public int Val { get; set; }
}
public void UsageSample()
{
var xmlSerializer = new XmlSerializer(typeof(MyClass));
var memoryStream = new MemoryStream();
var toSerialize = new MyClass { IgnoredVal = 1, Val = 2 };
xmlSerializer.Serialize(memoryStream, toSerialize);
memoryStream.Position = 0;
var deserialize = (MyClass)xmlSerializer.Deserialize(memoryStream);
Assert.AreEqual(0, deserialize.IgnoredVal);
Assert.AreEqual(2, deserialize.Val);
}
Nullify with reflection, code sample:
public void NullifyEntitySetProperties(object obj)
{
var entitySetProperties = obj.GetType().GetProperties()
.Where(property => property.PropertyType == typeof(EntitySet));
foreach (var property in entitySetProperties)
{
property.SetValue(obj, null, null);
}
}
In my opinion, if the first option can be done used in your code it's better. This option is more direct and economic.

Using Stored Procedures with Linq To Sql which have Additional Parameters

I have a very big problem and can't seem to find anybody else on the internet that has my problem. I sure hope StackOverflow can help me...
I am writing an ASP.NET MVC application and I'm using the Repository concept with Linq To Sql as my data store. Everything is working great in regards to selecting rows from views. And trapping very basic business rule constraints. However, I'm faced with a problem in my stored procedure mappings for deletes, inserts, and updates. Let me explain:
Our DBA has put a lot of work into putting the business logic into all of our stored procedures so that I don't have to worry about it on my end. Sure, I do basic validation, but he manages data integrity and conflicting date constraints, etc... The problem that I'm faced with is that all of the stored procedures (and I mean all) have 5 additional parameters (6 for inserts) that provide information back to me. The idea is that when something breaks, I can prompt the user with the appropriate information from our database.
For example:
sp_AddCategory(
#userID INT,
#categoryName NVARCHAR(100),
#isActive BIT,
#errNumber INT OUTPUT,
#errMessage NVARCHAR(1000) OUTPUT,
#errDetailLogID INT OUTPUT,
#sqlErrNumber INT OUTPUT,
#sqlErrMessage NVARCHAR(1000) OUTPUT,
#newRowID INT OUTPUT)
From the above stored procedure, the first 3 parameters are the only parameters that are used to "Create" the Category record. The remaining parameters are simply used to tell me what happened inside the method. If a business rule is broken inside the stored procedure, he does NOT use the SQL 'RAISEERROR' keyword when business rules are broken. Instead, he provides information about the error back to me using the OUTPUT parameters. He does this for every single stored procedure in our database even the Updates and Deletes. All of the 'Get' calls are done using custom views. They have all been tested and the idea was to make my job easier since I don't have to add the business logic to trap all of the various scenarios to ensure data quality.
As I said, I'm using Linq To Sql, and I'm now faced with a problem. The problem is that my "Category" model object simply has 4 properties on it: CategoryID, CategoryName, UserId, and IsActive. When I opened up the designer to started mapping my properties for the insert, I realized that there is really no (easy) way for me to account for the additional parameters unless I add them to my Model object.
Theoretically what I would LIKE to do is this:
// note: Repository Methods
public void AddCategory(Category category)
{
_dbContext.Categories.InsertOnSubmit(category);
}
public void Save()
{
_dbContext.SubmitChanges();
}
And then from my CategoryController class I would simply do the following:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
var category = new Category();
try
{
UpdateModel(category); // simple validation here...
_repository.AddCategory(category);
_repository.Save(); // should get error here!!
return RedirectToAction("Index");
}
catch
{
// manage friendly messages here somehow... (??)
// ...
return View(category);
}
}
What is the best way to manage this using Linq to Sql? I (personally) don't feel that it makes sense to have all of these additional properties added to each model object... For example, the 'Get' should NEVER have errors and I don't want my repository methods to return one type of object for Get calls, but accept another type of object for CUD calls.
Update: My Solution! (Dec. 1, 2009)
Here is what I did to fix my problem. I got rid of my 'Save()' method on all of my repositories. Instead, I added an 'Update()' method to each repository and actually commit the data to the database on each CUD (ie. Create / Update / Delete) call.
I knew that each stored procedure had the same parameters, so I created a class to hold them:
public class MySprocArgs
{
private readonly string _methodName;
public int? Number;
public string Message;
public int? ErrorLogId;
public int? SqlErrorNumber;
public string SqlErrorMessage;
public int? NewRowId;
public MySprocArgs(string methodName)
{
if (string.IsNullOrEmpty(methodName))
throw new ArgumentNullException("methodName");
_methodName = methodName;
}
public string MethodName
{
get { return _methodName; }
}
}
I also created a MySprocException that accepts the MySprocArgs in it's constructor:
public class MySprocException : ApplicationException
{
private readonly MySprocArgs _args;
public MySprocException(MySprocArgs args) : base(args.Message)
{
_args = args;
}
public int? ErrorNumber
{
get { return _args.Number; }
}
public string ErrorMessage
{
get { return _args.Message; }
}
public int? ErrorLogId
{
get { return _args.ErrorLogId; }
}
public int? SqlErrorNumber
{
get { return _args.SqlErrorNumber; }
}
public string SqlErrorMessage
{
get { return _args.SqlErrorMessage; }
}
}
Now here is where it all comes together... Using the example that I started with in my initial inquiry, here is what the 'AddCategory()' method might look like:
public void AddCategory(Category category)
{
var args = new MySprocArgs("AddCategory");
var result = _dbContext.AddWidgetSproc(
category.CreatedByUserId,
category.Name,
category.IsActive,
ref args.Number, // <-- Notice use of 'args'
ref args.Message,
ref args.ErrorLogId,
ref args.SqlErrorNumber,
ref args.SqlErrorMessage,
ref args.NewRowId);
if (result == -1)
throw new MySprocException(args);
}
Now from my controller, I simply do the following:
[HandleError(ExceptionType = typeof(MySprocException), View = "SprocError")]
public class MyController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Category category)
{
if (!ModelState.IsValid)
{
// manage friendly messages
return View(category);
}
_repository.AddCategory(category);
return RedirectToAction("Index");
}
}
The trick to managing the new MySprocException is to simply trap it using the HandleError attribute and redirect the user to a page that understands the MySprocException.
I hope this helps somebody. :)
I don't believe you can add the output parameters to any of your LINQ classes because the parameters do not persist in any table in your database.
But you can handle output parameters in LINQ in the following way.
Add the stored procedure(s) you whish to call to your .dbml using the designer.
Call your stored procedure in your code
using (YourDataContext context = new YourDataContext())
{
Nullable<int> errNumber = null;
String errMessage = null;
Nullable<int> errDetailLogID = null;
Nullable<int> sqlErrNumber = null;
String sqlErrMessage = null;
Nullable<int> newRowID = null;
Nullable<int> userID = 23;
Nullable<bool> isActive=true;
context.YourAddStoredProcedure(userID, "New Category", isActive, ref errNumber, ref errMessage, ref errDetailLogID, ref sqlErrNumber, ref sqlErrMessage, ref newRowID);
}
I haven' tried it yet, but you can look at this article, where he talks about stored procedures that return output parameters.
http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx
Basically drag the stored procedure into your LINQ to SQL designer then it should do the work for you.
The dbContext.SubmitChanges(); will work only for ENTITY FRAMEWORK.I suggest Save,Update and delete will work by using a Single Stored procedure or using 3 different procedure.

Resources