im just creating my first MVC applicaiton and am having trouble connecting to my database located on my sql server.
i have added the connection string to the web config as normal, created a model with all the fields in.
i created a model and created a new DBContext as there wasnt one listed. this created the below file
im not sure how it connects to the right table in my SQLDB, how do i do this?
also how do i make it run stored procedures?
Thanks
public EquipmentDBContext()
: base("name=ITAPPConnectionString")
{
}
public DbSet<Equipment> Equipments { get; set; }
public EquipmentDBContext()
: base("name=ITAPPConnectionString")//this name should be the name of database
{
}
public DbSet<Equipment> Equipments { get; set; }
here you say you have a
Datamodoel called Equipment. Your context also defines a single property, Equipments, which is of type DbSet. This property acts as a collection that allows you to query the data in you table in database as though it were an in-memory collection of objects.
So, if you create an object of class EquipmentDbContext in controller named lets say db, then you can access the data in table with something like
db.Equipments
To expand further on Cybercop's answer you would do something like this
using (var context = new EquipmentDBContext())
{
var equipments = context.Equipments.ToList();
var equipment = context.Equipments.FirstOrDefault(c=>c.Id == 1);
var blueThings= context.Equipments.Where(c=>c.Color == "blue").ToList();
}
Related
In an ASP.NET MVC web application, I have created the following entity:
[Table("tblEmployee")]
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
}
But, when I try to retrieve data from a database table called tblEmployee using Entity Framework, I get an error. What I have done until now is:
Created a database MVCDemo with "." as server name and using Windows authentication containing a table called tblEmployee
Installed Entity Framework
Added EmployeeContext.cs class file to Models folder
Code:
namespace MVCDemo.Models
{
public class EmployeeContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
}
}
Added a connection string to web.config file in the root directory
<connectionSrtings>
<add name="EmployeeContext"
connectionString="server=.; database=MVCDemo; integrated security=SSPI"
providerName="System.Data.SqlClient;" />
</connectionSrtings>
Added Details actionResult to EmployeeController to show employee details:
namespace MVCDemo.Controllers
{
public class EmployeeController : Controller
{
// GET: Employee
public ActionResult Details(int id)
{
EmployeeContext employeeContext = new EmployeeContext();
Employee employee = employeeContext.Employees.Single(e => e.EmployeeId == id);
return View(employee);
}
}
}
Finally, I added the following code to Global.asax to prevent initialization:
Database.SetInitializer<MVCDemo.Models.EmployeeContext>(null);
The problem is when I run the application I get this error:
HTTP Error 500.19 - Internal Server Error
The requested page cannot be accessed because the related configuration data for the page is invalid.
and when I comment connection strings out and try to reach
http://localhost:60613/Employee/Details/1
to show details of 1st employee, I get this error:
System.Data.Entity.Core.EntityException: 'The underlying provider failed on Open.'SqlException: Cannot attach the file 'C:\Users\arya\source\repos\MVCDemo\MVCDemo\App_Data\MVCDemo.Models.EmployeeContext.mdf' as database 'MVCDemo.Models.EmployeeContext'.
Check your tag name, it is incorrect. It will trigger the error definitely.
<connectionSrtings>
It should be:
<connectionStrings>
Update:
Since you have another issue, fix the last part of your connection string:
providerName="System.Data.SqlClient;
Remove the semi-colon at the end of SqlClient.
This is because if you have the database named MVCDemo in the SQL Server then its fine, otherwise code first approach looking for MVCDemo database in SQL Server. If you dont have the database in SQL Server, then try this connection string to create the mdf file first.
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-MVCDemo-20200820010246.mdf;Initial Catalog=aspnet-MVCDemo-20200820010246;Integrated Security=True"
First of all, I couldn't see your database connection. Yes you have teached the table but you didn't tell the program where to put those infos. Something like:
optionsBuilder.UseSqlServer("Data Source=databaseName")
Second possible reason is your program don't know where to go at the beginning. I had those error before and solved it with using default map.
Third reason, this probably not true but, you wrote "connectionSrtings" wrong. As I say, it's probably not that but I wanted to mention if it is.
The tutorials on enabling authentication work all right, but what identifier should be used to store data for a user in the database? The only thing easily available is User.Name, which seems to be my email address.
I see in the database there is an AspNetUsers table with that as the UserName column, and a varchar Id column that appears to be a GUID and is the primary key. It seems like the 'Id' field is the logical value to use, but it's not readily available in my app. I found I can get to it like this:
string ID_TYPE = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
var id = User.Claims.Where(x => x.Type == ID_TYPE).Select(x => x.Value).FirstOrDefault();
But that seems like a weird way to go about it. Is that the proper value to use say if I want to create a 'Posts' table that has a user associated with a post?
I've looked at these pages and it seems that a lot of this might be due to Microsoft integrating the same login process with ActiveDirectory.
Is there a reason to make the id so hard to get to and the name so easy? Should I be using the name instead? Should I be careful not to let the user change their user name then?
The shortest path to UserId is:
User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
Or create extension like so if you need to access UserId a lot:
public static class ClaimsPrincipalExtensions
{
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
return null; //throw new ArgumentNullException(nameof(principal));
string ret = "";
try
{
ret = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
}
catch (System.Exception)
{
}
return ret;
}
}
Usage:
User.GetUserId()
In your controller use dependency injection to get the user manager:
Create a class MyUser that has your extended properties
public class MyUser : IdentityUser
{
public string MyExendedInfo { get; set; }
public int MyOtherInfo {get;set;}
}
add this property to the database using migration, or manually add it.
In Startup.cs in Configure Services add:
services.AddIdentity<MyUser, IdentityRole>()
Now inject this in your controller class:
private readonly UserManager<MyUser> _userManager;
public HomeController(
UserManager<MyUser> userManager)
{
_userManager = userManager;
}
Now you can access your additional proporties and your Id (if you still need this) in your action methods like this:
var user = await _userManager.GetUserAsync(HttpContext.User);
var id = user.Id;
var myExtendedInfo = user.MyExtendedInfo;
var myOtherInfo = user.MyOtherInfo;
etc
You can also update information about your user:
user.myExtendedInfo = "some string";
user.MyOtherInfo = myDatabase.pointer;
var result = await _userManager.UpdateAsync(user);
if (!result.Succeeded)
{
//handle error
}
So as long as you want only limited additional data stored in the database, you can create a custom user class, and use the Identity system to store it for you. I would not store it myself.
If however, you need to store large information in a separate table and/or reference the user from other tables, the Id is the correct field to use and you can access it as shown above.
I don't know what the best practice is for how much information can be stored in AspNetUsers, versus in claims, versus in your own table, but since the provided table already stores things like user name, phonenumber etc, I think it is Ok to extend it like this.
I am developing a site in which nhibernate is using. that is working fine for static mapping. but problem that i apply this application on existing database. so is there any way that mapping of classes took place at run time. i mean user provide tables and column names for mapping. Thanks
From your question I interpret you saying that the POCO classes exists, but you don't know the table or column names at build time.
So, if you already had this class:
public class MyGenericClass
{
public virtual long Id { get; set; }
public virtual string Title { get; set; }
}
You could bind it to a table and columns at runtime:
string tableName; // Set somewhere else by user input
string idColumnName; // Set somewhere else by user input
string titleColumnName; // Set somewhere else by user input
var configuration = new NHibernate.Cfg.Configuration();
configuration.Configure();
var mapper = new NHibernate.Mapping.ByCode.ModelMapper();
mapper.Class<MyGenericClass>(
classMapper =>
{
classMapper.Table(tableName);
classMapper.Id(
myGenericClass => myGenericClass.Id,
idMapper =>
{
idMapper.Column(idColumnName);
idMapper.Generator(Generators.Identity);
}
);
classMapper.Property(c => c.Title,
propertyMapper =>
{
propertyMapper.Column(titleColumnName);
}
);
}
);
ISessionFactory sessionFactory = configuration.BuildSessionFactory();
ISession session = sessionFactory.OpenSession();
////////////////////////////////////////////////////////////////////
// Now we can run an SQL query over this newly specified table
//
List<MyGenericClass> items = session.QueryOver<MyGenericClass>().List();
I don't think that could be possibly with NHibernate, but you could use a workaround.
You could use a view instead a table for the NHibernate mapping.
And in runtime, you could create that View or update it with the especified user mapping you need.
For example, you define a mapping in NHibernate to a view named ViewMapped with two columns Name and Mail.
And in the other hand, the user has a table with three columns Name, SecondName, EMail.
you can create a view on runtime with the following select:
(SELECT Name + ' ' + SecondName as Name, EMail as Mail FROM tableName) AS ViewMapped
I hope that helps you, or at least leads you to a solution.
I need to group some data from a SQL Server database and since LightSwitch doesn't support that out-of-the-box I use a Domain Service according to Eric Erhardt's guide.
However my table contains several foreign keys and of course I want the correct related data to be shown in the table (just doing like in the guide will only make the key values show). I solved this by adding a Relationship to my newly created Entity like this:
And my Domain Service class looks like this:
public class AzureDbTestReportData : DomainService
{
private CountryLawDataDataObjectContext context;
public CountryLawDataDataObjectContext Context
{
get
{
if (this.context == null)
{
EntityConnectionStringBuilder builder = new EntityConnectionStringBuilder();
builder.Metadata =
"res://*/CountryLawDataData.csdl|res://*/CountryLawDataData.ssdl|res://*/CountryLawDataData.msl";
builder.Provider = "System.Data.SqlClient";
builder.ProviderConnectionString =
WebConfigurationManager.ConnectionStrings["CountryLawDataData"].ConnectionString;
this.context = new CountryLawDataDataObjectContext(builder.ConnectionString);
}
return this.context;
}
}
/// <summary>
/// Override the Count method in order for paging to work correctly
/// </summary>
protected override int Count<T>(IQueryable<T> query)
{
return query.Count();
}
[Query(IsDefault = true)]
public IQueryable<RuleEntryTest> GetRuleEntryTest()
{
return this.Context.RuleEntries
.Select(g =>
new RuleEntryTest()
{
Id = g.Id,
Country = g.Country,
BaseField = g.BaseField
});
}
}
public class RuleEntryTest
{
[Key]
public int Id { get; set; }
public string Country { get; set; }
public int BaseField { get; set; }
}
}
It works and all that, both the Country name and the Basefield loads with Autocomplete-boxes as it should, but it takes VERY long time. With two columns it takes 5-10 seconds to load one page.. and I have 10 more columns I haven't implemented yet.
The reason it takes so long time is because each related data (each Country and BaseField) requires one request. Loading a page looks like this in Fiddler:
This isn't acceptable at all, it should be a way of combining all those calls into one, just as it does when loading the same table without going through the Domain Service.
So.. that was a lot explaining, my question is: Is there any way I can make all related data load at once or improve the performance by any other way? It should not take 10+ seconds to load a screen.
Thanks for any help or input!s
My RIA Service queries are extremely fast, compared to not using them, even when I'm doing aggregation. It might be the fact that you're using "virtual relationships" (which you can tell by the dotted lines between the tables), that you've created using your RuleEntryTest entity.
Why is your original RuleEntry entity not related to both Country & BaseUnit in LightSwitch BEFORE you start creating your RIA entity?
I haven't used Fiddler to see what's happening, but I'd try creating "real" relationships, instead of "virtual" ones, & see if that helps your RIA entity's performance.
I have a simple database model containing 3 Tables : Companies, Categories and CompanyCategories (which is a relation table with only 2 FK : CompanyID and CategoryID).
My edmx model it only shows Companies and Categories tables (CompanyCategories is somehow hidded since its a simple many to many relationship table).
In the WCF service, I have a GetDatabase() function that returns all the database objets wrapped in one big custom object :
[OperationContract]
public FullDatabase GetDatabase()
{
DBEntities context = new DBEntities ();
FullDatabase mydb = new FullDatabase();
mydb.Companies = context.Companies.ToList();
mydb.Categories = context.Categories.ToList();
return mydb;
}
[OperationContract]
public FullDatabase UpdateDatabase(FullDatabase db)
{
// Here is my problem when removing a category from a company on
// the client its been brought back in my db object
}
class FullDatabase()
{
List<Company> Companies;
List<Category> Categories;
}
On the client now, I use GetDatabaseAsync() to retrieve the database in a _FullDB variable. Now using that variable I tried the following :
// Adding a category like that Works well
Company c = _FullDB.Companies.First();
c.Categories.Add(_FullDB.Categories.First());
wcfServiceClientObject.UpdateDatabaseASync(_FullDB);
.....
// Removing a category, doesn't work though :
Company c = _FullDB.Companies.First();
c.Categories.Remove(_FullDB.Categories.First());
wcfServiceClientObject.UpdateDatabaseASync(_FullDB);
// here my c.Categories.Count is updated correctly to delete the item
// but when on the server after (in the UpdateDatabase function) the item
// I deleted is still there
I really dont understand why the Add would work but not the Remove.
Finally found the problem. Now it works, but I'm not sure it is the best way to do it.
When removing the category from the company, I also had to also remove the company from the category...
Company comp = _FullDB.Companies.First();
Category cat = _FullDB.Categories.First();
comp.Categories.Remove(cat);
cat.Companies.Remove(comp);
wcfServiceClientObject.UpdateDatabaseASync(_FullDB);