I'm creating a web app based on a database. The datas in the database need to be displayed, edited and deleted by the web app user.
Right now I need to remove elements in my sqlite database table after the user inputs the name of the database table and the id (which is also the primary key) of the element. How can I do it?
I always used Entity Framework before and also in the Web App so I was looking for a solution with it, but if there's a simpler way to do it, I'll stick with it.
Thank you
I think the answer here is similar but I need help to adapt it to what I need now.
Entity Framework C# queries from strings
this is the UI
and here is the endpoint in the backend
//DELETE method
[HttpDelete("DeleteElementInTable")]
public IActionResult DeleteElementInTable(string tableName, string elementKey) //url query parameters
{
var db = new MyContext();
//code to remove the item ... something like:
DbManager.RemoveElement(tableName, elementKey); //DbManager is the static class dealing with the db context
return //csv of the deleted element;
}
I'm still a young developer but here I can see there are some lacks of knowledge. First of all, which technology are you using to build your web-app? From what you posted my guess is you are trying to use MVC. As #Panagiotis Kanavos said above you need an entity to interact with the database if you want to use Entity Framework, through which you don't need to pass table name in your GET function. Last but not less important you can't execute the delete operation in a GET function.
Related
I want to make a universal method for working with tables. Studied links
Dynamically Instantiate Model object in Entity Framework DB first by passing type as parameter
Dynamically access table in EF Core 2.0
As an example, the ASP.NET CORE controller for one of the SQL tables is shown below. There are many tables. You have to implement such (DEL,ADD,CHANGE) methods for each table :
[Authorize(Roles = "Administrator")]
[HttpPost]
public ActionResult DeleteToDB(string id)
{
webtm_mng_16Context db = new webtm_mng_16Context();
var Obj_item1 = (from o1 in db.IT_bar
where o1.id == int.Parse(id)
select o1).SingleOrDefault();
if ((Obj_item1 != null))
{
db.IT_bar.Remove(Obj_item1);
db.SaveChanges();
}
var Result = "ok";
return Json(Result);
}
I want to get a universal method for all such operations with the ability to change the name of the table dynamically. Ideally, set the table name as a string. I know that this can be done using SQL inserts, but is there really no simple method to implement this in EF CORE
Sorry, but you need to rework your model.
It is possible to do something generic as long as you have one table per type - you can go into the configuration and change the database table. OpenIddict allows that. You can overwrite the constructors of the DbContext and play whatever you want with the object model, and that includes changing table names.
What you can also do is a generic base class taking the classes you deal with as parameters. I have those - taking (a) the db entity type and (b) the api side dto type and then using some generic functions and Automapper to map between them.
But the moment you need to grab the table name dynamically you are in a world of pain. EF standard architecture assumes that an object type is mapped to a database entity. As such, an ID is unique within a table - the whole relational model depends on that. Id 44 has to be unique, for a specific object, not for an object and the table it was at this moment loaded from.
You also miss up significantly on acutally logic, i.e. for delete. I hate to tell you, but while you can implement security on other layers for reading, every single one of my write/update methods are handwritten. Now, it may seem that "Authorize" works - but no, it does not. Or - it does if your application is "Hello world" complex. I run sometimes pages of testing code whether an operation is allowed in a specific business context and this IS specific, whether the user has set an override switch (which may or may not be valid depending on who he is) do bypass certain business rules. All that is anyway specific.
Oh, what you can also do... because you seem to have a lot of tables: do NOT use one class, generate them. Scaffolding is not that complex. I hardly remember when I did generate the last EF core database classes - they nowadays all come out of Entity Developer (tool from Devart), while the db is handled with change scripts (I work db first - i actually want to USE The database and that means filtered indices, triggers, some sp's and views with specific SQL), so migrations do not really work at all.
But now, overwriting the table name dynamically - while keeping the same object in the background - will bite you quite fast. It likely only works for extremely simplistic things - you know, "hello world" example - and breaks apart the moment you actually have logic.
This may be a bit silly, but all the applications I've built have always utilized the EF Code-First approach to generate the database. When using this method, I've always accessed the database through the Context:
public class RandomController : Controller
{
public CombosContext db = new CombosContext();
//
// GET: /Home/
public ActionResult Index()
{
var rows = db.Combos.OrderBy(a => a.Id).ToList();
However, what if the database is already created for me, OR I create one by adding entities to the schema/design surface and then generate the database from that. How would I access the db without the
public CombosContext db = new ComboxContext();
If the DB is already created, you can use the Database First approuch: http://blogs.msdn.com/b/adonet/archive/2011/09/28/ef-4-2-model-amp-database-first-walkthrough.aspx
A basic setup would by to rightclick the project in the solution explorer and click Add > new item. On the dialog, select Data on the left pane and ADO.net Entity Data Model and follow the wizard to create your model based on the database. This way, you will have a context object exactly the way you have with code first (with some minor changes, but works almost the same).
You can still do this with Code first and is the better approach IMHO. Use the Entity Framework Power Tools to reverse engineer your existing database into a code-first model.
http://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d/
See my demo on using it at:
http://channel9.msdn.com/Events/TechEd/NorthAmerica/2012/DEV215
I am using Entity Framework with WCF Data Services and I have the following table in my database :
Table Contract
Id (int)
Name (varchar)
byUser (varchar)
isDeleted (bit)
Entity Framework class
Id (int)
Name(string)
byUser(string)
isDeleted(boolean)
whenever the user is inserting/updating/deleting a contract(through a client app), I need to log who did the action.
so, I created Stored procedures for insert/update/delete that will receive the username from the client when an insertion/deletion/update is performed.
the issue is that the delete operation does not send over who is performing the operation :
var ctx = Context;
var contractToDelete = ctx.Contracts.Where(c => c.ContractId == 1).First();
contractToDelete.ByUser = username;
ctx.DeleteObject(contractToDelete);
ctx.SaveChanges();
at the server side, the byUser is always null.
Questions :
1) How do I make it so that the byUser parameter is sent to the server ?
2) Is there a better way to handle this kind of scenario ? (logging/authentication/authorization) with Entity Framework
It doesn't send null "always". It sends the old value always. That is some internal logic in entity framework. For each tracked object EF keeps both original and current values. When you are deleting object EF doesn't use current values - it uses original values (don't ask me why, simply this is how it works).
So you need to cheat EF:
var ctx = Context;
var contractToDelete = ctx.Contracts.Where(c => c.ContractId == 1).First();
contractToDelete.ByUser = username;
ctx.Contracts.ApplyOriginalValues(contractToDelete);
ctx.DeleteObject(contractToDelete);
ctx.SaveChanges();
Calling ApplyOriginalValues will force EF to override original values with values passed in parameter = you will override original values with current values.
In my opinion the better way is storing deleted records in separate table because it will avoid a lot of problems with passing isDeleted=false to every query where both eager and lazy loading will load deleted records as well. The only way to avoid problems with isDeleted is using conditional mapping but in such case you will not be able to load deleted records even if you want to unless you use stored procedures or direct SQL queries.
The way I managed this is, when my user logs in, I store basic information about them in the session. I then have a class that sits on top of my actions to context.
Whenever I commit back changes, I go through the same routine which checks what changed. I developed the ability to trigger actions based upon the entity being worked with (so I can keep an eye on something such as contracts). Then I have the user able to be logged.
[Edit]
This is tougher to clarify than I realised, but I'll try.
I'm creating a web application. Heavily using Ninject.
When the user logs in, I store their information in an IUserSession object (this is really held in Session, but a custom Ninject scope makes this neat for me and prevents me from having to expose my data layer to Web Session). This user session object contains username, user id etc.
I created a class that contains the context,and wraps all the SELECT,CREATE,DELETE and COMMIT calls. i.e. SELECT;
public IQueryable<TEntity> All<TEntity>( ) {
return Context.Set<TEntity>();
}
This class also has a Commit method, this is the call to SaveChanges.
Before calling SaveChanges, you have access to the changes in the form of Context.ChangeTracker.Entities
For each entity that has changed, you can test to see if it was added, deleted or modified.To get the type of the element being modified;
Type baseEntityType = ObjectContext.GetObjectType( entity.Entity.GetType( ) );
I do plan on writing up a tutorial soon, based upon my personal experience with doing this (not that that helps you right now).
I have a library which uses EF4 for accessing a SQL Server data store. For different reasons, I have to use SQL Server specific syntax to read data from the store (for free text search), so I have to create the SQL code by hand and send it through the ExecuteStoreQuery method.
This works fine, except that the query uses joins to request several tables aside the main one (the main one being the one I specify as the target entity set when calling ExecuteStoreQuery), and EF never fills up the main entity's relationship properties with the other table's data.
Is there anything special to do to fill up these relationships? Using other EF methods or using special table names in the query or something?
Thanks for your help.
Executing direct SQL follows very simple rule: It uses column from the result set to fill the property with the same name in materialized entity. I think I read somewhere that this works only with the the main entity you materialize (entity type defined in ExecuteStoreQuery = no relations) but I can't find it now. I did several tests and it really doesn't populate any relation.
Ok so I'll write here what I ended up doing, which does not looks like a perfect solution, but it does not seem that there is any perfect solution in this case.
As Ladislav pointed out, the ExecuteStoreQuery (as well as the other "custom query" method, Translate) only maps the column of the entity you specify, leaving all the other columns aside. Therefore I had to load the dependencies separately, like this :
// Execute
IEnumerable<MainEntity> result = context.ExecuteStoreQuery<MainEntity>(strQuery, "MainEntities", MergeOption.AppendOnly, someParams).ToArray();
// Load relations, first method
foreach (MainEntity e in result)
{
if (!e.Relation1Reference.IsLoaded)
e.Relation1Reference.Load();
if (!e.Relation2Reference.IsLoaded)
e.Relation2Reference.Load();
// ...
}
// Load relations, second method
// The main entity contains a navigation property pointing
// to a record in the OtherEntity entity
foreach(OtherEntity e in context.OtherEntities)
context.OtherEntities.Attach(e);
There. I think these two techniques have to be chosen depending on the number and size of generated requests. The first technique will generate a one-record request for every required side record, but no unnessecary record will be loaded. The second technique uses less requests (one per table) but retrieves all the records so it uses more memory.
In order to acces my db and use my stored procedures I made this very simple data access layer (if someone can call this "layer"). I have 8 files where each file looks like:
using System;
using System.Data;
using System.Data.Common;
using Microsoft.Practices.EnterpriseLibrary.Data;
public class TasksDBHandler
{
private static Database db = DatabaseFactory.CreateDatabase("DBNAME");
public static void SetTaskDepreciationData(long taskId, long fieldId, string value)
{
DbCommand command = db.GetStoredProcCommand("dbo.P_CUS_TSK_SetTaskDepreciationData");
db.AddInParameter(command, "#task_id", DbType.Int64, taskId);
db.AddInParameter(command, "#field_id", DbType.Int64, field);
db.AddInParameter(command, "#value", DbType.String, value);
db.ExecuteNonQuery(command);
}
//Many more stored procedures calls
}
I want to build a new and better data access layer but I don't know how should it look like. I want the ability to use stored procedures without the need to write static method for each stored procedure, I want better connection menagement and so on/
Is anyone have any clue how to do so?
I am using .Net and SQL SERVER.
Have you looked at any of the ORM products out there? There's Linq2Sql, Entity Framework, NHibernate, and others. Unless what you need to do is very basic, you'll probably have better results learning to use an existing framework than trying to write your own.
In an ORM like Entity Framework, you typically don't manage your connection manually, it defines an object (or entity) model from your database and a "context" which is responsible for retrieving the data from your database and mapping it to the correct properties on the classes in your entity model. So you request something from the context, it loads the data necessary to fulfill your request into memory, you work with it like other classes, and then tell the context to save your changes back to the database. There are several ways to interact with your entity model in entity framework, but the example I'll use is Linq2Entities. You write a Linq query, and the context is responsible for turning that into a query against the database *disclaimer: I haven't tried to run this code, it's just meant to serve as an example
using(MyEntitiesContext context = new MyEntitiesContext())
{
var idleUsers = from u in context.User
where u.LoggedIn && u.LastActivity > DateTime.Now.AddMinutes(-30)
select u;
foreach(User u in idleUsers)
{
u.Status = UserStatus.Idle;
}
context.SaveChanges();
}
Obviously there's a lot going on behind the scenes:
There's the whole object model that gets generated from your database (you select the tables you want to be included in your model, and you can create multiple models in the same project).
There's the context, which manages the database connection and turns your Linq expression into a database query
There's the connection string that has to be defined your .config file so Entity Framework knows how to connect to your database
You should be able to find plenty of information on Entity Framework, but the easiest way I've found to learn is to jump in and start trying to do something, and then find answers to questions as they come up. I wouldn't try to use it right away on something highly critical or time sensitive, as there's definitely a learning curve, and you'll learn better ways of working with it once you've experienced some of the pitfalls.
Here's a link to Microsoft's Entity Framework 4 Quickstart which should give you something fairly straightforward to try out. Have fun!