Is it possible to have another object type as a property of SQL Server entity without using relation - sql-server

I have smaller separate models I don't want to map to SQL Server database table. Is it possible to use them as properties of an object that's mapped to SQL Server table?
I know SQL Server is relational, but of a case where I don't to map these separate models to database table? I have done it several times with non relational databases like MongoDb.
Here is and example what I want to achieve
The DbContext class:
public class ApplicationDbContext: DbContext
{
....
public DbSet<User> Users {get; set;}
}
User class:
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public LoginProfile LoginProfile { get; set; }
}
LoginProfile class:
public class LoginProfile
{
public string Username { get; set; }
public string Password { get; set; }
}
In the above example User model class is the only one I want to have as table in my database. Is it possible to do that, and do things like
var password = user.LoginProfile.Password;
user.LoginProfile.username = "username";

Related

EmployeeDataContext class not pulling data from Database

below is my code
I am trying to pull data from database using entityframework.
EmployeeDataContext class -
namespace _09032020_1.Models
{
public class EmployeeDataContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
}
}
Employee model -
namespace _09032020_1.Models
{
[Table("TbleEmployee")]
public class Employee
{
public int employeeId { get; set; }
public string employeeName { get; set; }
public string employeeCity { get; set; }
public string employeeGender { get; set; }
public int departmentId { get; set; }
}
}
below are the table columns.
here is the controller code
namespace _09032020_1.Controllers
{
public class EmployeeController : Controller
{
public ActionResult Index()
{
EmployeeDataContext employeeDataContext = new EmployeeDataContext();
Employee employee = new Employee();
List<Employee> employees1 = new List<Employee>();
employees1 = employeeDataContext.Employees.ToList();
return View(employees1);
}
}
}
I am not getting data inside employeeDataContext
Please let me know if more info regarding config file requires.
Create the table w data. The first column is primary key and identity.
In an MVC project (you can use another type, also I am showing database first, and you can use another type, right click on the Models folder and add ADO.NET Entity Data Model named EmployeeDataContext. Choose EF Designer from database. New connection, and choose your db. Save connection as EmployeeDataContext and choose your table.
Put this in your code:
using (EmployeeDataContext context = new EmployeeDataContext())
{
var emps = context.Employees.ToList();
}
I got my answer,
I have written wrong table name as model attribute [Table("TbleEmployee")]
My table name is TblEmplyee. So it should be [Table("TblEmployee")]
As I changed this I abled to proceed forward.

Null data returned using a 1:1 model

I have two SQL tables, User and UserType joined with UserType as a foreign key, with their respective models in ASP. To my understanding, this should be a 1:1 relationship (correct me if I'm wrong). One unique user, set as a type of user (being admin, super admin, user etc).
When I try and retrieve a list of users, it returns a null on the property UserType.
I used Google to get this far, but I'm struggling to get this particular issue fixed.
At one point I got an error stating: "Unable to determine the principal end of an association". To get around that, I included a Required annotation (didn't work) and a ForeignKey annotation (didn't work either) in both models, both simultaneously and separately.
This is what I have so far.
[Table("Users", Schema = "dbo")]
public class Users
{
[Key, ForeignKey("UserType")]
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string ContactNumber { get; set; }
public UserType UserType { get; set; }
public string IsActive { get; set; }
}
[Table("UserType", Schema = "dbo")]
public class UserType
{
[Key]
public Guid Id { get; set; }
public string Type { get; set; }
public string Description { get; set; }
public string IsActive { get; set; }
public Users Users { get; set; }
}
I'm using the below LINQ method to retrieve the data:
public PagedTables<Users> GetAllUsers(Pagination pagination)
{
using (var db = new DbContext())
{
var user = new PagedTables<Users>()
{
Data = db.Users.OrderBy(U => U.Id).Skip(pagination.Page).Take(pagination.Limit).ToList(),
Count = db.Users.Count()
};
return user;
}
}
A break point on the users var shows that the property UserType returns null. I would expect the assigned user type to be joined onto the user.
Any help would be appreciated. Thanks
My EF background is database-first but if you are eager loading (i.e. not lazy loading) then are you missing an Include to tell LINQ to go and get the UserType? Something like;
Data = db.Users.OrderBy(U => U.Id).Skip(pagination.Page).Take(pagination.Limit).Include(U => U.UserType).ToList(),

How to to make entity relationships in WEB API database?

I'm making a task management tool using AngularJS for the frontend and ASP.NET WEB API 2 for the backend. I have two entities in the database, a "Task" and a "Type". Each task has one type associated. The user fills a form when he can create a new task, and he has to select a type for that task.
Here's the C# code:
// KBTM_Task.cs file
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
}
// KBTM_Type.cs file
public class KBTM_Type
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
So my question is: how do I "connect" the two in the database? What I mean is, let's say I want to POST data to the database. I have to make two POSTs, right? One for the Task and one for the Type, since they're two separate entities.
But since they're stored with two different IDs, how do I know that a certain task has a certain type? In other words, if I send a GET request to KBTM_Task, how do I get the type of that task?
Modify your KBTM_Task entity to include the Type Id and foreign key relationship
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
public int TypeID { get; set; }
[ForeignKey("TypeID")]
public virtual KBTM_Type Type { get; set; }
}
This way when you get the data from the API your task object will already include the key ("TypeID") that can be updated and related object ("Type") that you can access its properties (Name, Description, ...).
When you update TypeID on the client object (model) you can simply push the updated task object to the API using $http.put() to handle the database update.
1) Add foreign key using fluent api (or data annotation)
// KBTM_Task.cs file
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
public int KBTM_TypeID {get;set}
public virtual KBTM_Type {get; set}
}
// KBTM_Type.cs file
public class KBTM_Type
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public KBTM_Task KBTM_Task { get; set;}
}
Add the following in the class inheriting from DbContext
public class KbtmContext : DbContext
{
...
//public virtual DbSet<KBTM_Task> KbtmTasks {get; set;}
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure KBTM_TypeID as FK for KBTM_Task
modelBuilder.Entity<KBTM_Task>()
.HasRequired(k => k.KBTM_Type)
.WithRequiredPrincipal(ad => ad.KBTM_Task);
}
}
2) If exposing the entity class in API response or request then you need to exclude navigation property from being serialized.
// KBTM_Task.cs file
public class KBTM_Task
{
...
[JsonIgnore]
public virtual KBTM_Type Type { get; set; }
}
To use the [JsonIgnore] atttribute use Install-Package Newtonsoft.Json in package manager console.(One of the popular solutions to manage serialization)

Showing specific data based on the currently logged in user

I have a question that deals with the logistics of returning rows of data in a SQL database (Entity Framework) based on the user that is logged in; I have mainly focused on desktop C# applications and while making the switch to ASP.NET MVC 4 I'm having a bit of difficulty when it comes to figuring this out (I've searched around and none of the answers seem to provide exactly what I'm looking for):
I would like to use the authorization built in to ASP.NET (MVC4), and allow users to post data about their websites (site category, url, age, etc.) with a form, and have the form store the data (using Entity Framework) to a database (called PrimaryDomainsDb) that is tied to their Id in the UserProfile table.
When the user clicks a button to show their list of domains, how can I make the application pull their list of domains (relevant rows of data) while ignoring other users rows?
Again, I'm mainly looking for the logistics and concepts (using foreign keys, for example) and psuedocode rather than actually spoonfeeding me a bunch of code.
If anyone has any best practice ideas (i.e. link the UserProfile to the PrimaryDomainDb this way, and use EF to call the rows matching their Id this way to return the rows to the View), it would be much appreciated.
Some sample code:
I currently have my PrimaryDomain code first set up like this (this doesn't have the decorators that specify min/max length, etc.):
public class PrimaryDomain
{
public virtual int Id { get; set; }
public virtual string SiteName { get; set; }
public virtual string SiteURL { get; set; }
public virtual SitePlatforms SitePlatform { get; set; }
public virtual decimal? SiteDA { get; set; }
public virtual decimal? SitePA { get; set; }
public virtual string SiteAge { get; set; }
public virtual DateTime? LastStatusUpdate { get; set; }
public virtual string SiteIP { get; set; }
}
And I have a User class that is different than the one provided by ASP.NET WebSecurity, that looks like this: (also, I know that "password" should not be in string formatting, this is just for initial set-up purposes - and password should probably be removed altogether and handled by WebSecurity, I think).
public class User
{
public virtual int Id { get; set; }
public virtual string Username { get; set; }
public virtual string Password { get; set; }
public virtual string Email { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string MozAccessID { get; set; }
public virtual string MozKey { get; set; }
public virtual decimal AccuountBalance { get; set; }
public virtual PrivateProxy PrivateProxies { get; set; }
public virtual PrimaryDomain PrimaryDomains { get; set; }
}
When pulling the data for Views I run everything through a repository using direct injection:
public interface IUserDataSource
{
IQueryable<User> Users { get; }
IQueryable<PrimaryDomain> PrimaryDomains { get; }
void Save();
}
This is my UserDb class, which is fed in whenever the code calls for an IUserDataSource (via direct injection):
public class UserDb : DbContext, IUserDataSource
{
public UserDb()
: base("DefaultConnection")
{
}
public DbSet<User> Users { get; set; }
public DbSet<PrimaryDomain> PrimaryDomains { get; set; }
IQueryable<User> IUserDataSource.Users
{
get { return Users; }
}
IQueryable<PrimaryDomain> IUserDataSource.PrimaryDomains
{
get { return PrimaryDomains; }
}
void IUserDataSource.Save()
{
SaveChanges();
}
}
And this is, for example, how I would pass the PrimaryDomains model to the View:
public class NetworkController : Controller
{
//
// GET: /Network/
private IUserDataSource _db;
public NetworkController(IUserDataSource db)
{
_db = db;
}
public ActionResult ListDomains()
{
var allDomains = _db.PrimaryDomains;
return View(allDomains);
}
}
But instead of pulling the entire PrimaryDomains list from the data source, I would like to add a way to reference the currently logged in user id to make the application only show the domains for that specific user, not all domains, and when adding a new domain via the form to reference the User Id and add it into the table as well.
My original question may have caused some confusion as to what I'm trying to achieve; It's my fault for posing the wrong way of going about what I'm trying to do. After much research and learning, I've found that exactly what I'm looking for is a multi-tenant data architecture approach.
This is probably what you are looking for. If I understood you correctly you want to use WebSecurity to login or register users but you want to use entity framework to store some user-specific data. Code below connects WebSecurity tables with your database CodeFirst created using EntityFramework.
You create class below (from tutorial).
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Ensure ASP.NET Simple Membership is initialized only once per app start
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
try
{
if(!WebSecurity.Initialized)
WebSecurity.InitializeDatabaseConnection("ConnectionString", "DbUsers", "UserId", "Email", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
}
}
It creates necessary tables for registering and logging your users. The magic is in second, third and fourth parameter. It is respectively table, userId column and userName column from YOUR database that you can create by EntityFramework. WebSecurity uses that table along with other self-generated tables to manage your users and let them register, login and so on.
Then in your code first you simply create table
public class DbUser
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[MaxLength(40)]
public string Email { get; set; }
[MinLength(3)]
[MaxLength(30)]
[Required]
public string FirstName { get; set; }
[MinLength(3)]
[MaxLength(50)]
[Required]
public string LastName { get; set; }
}
Then you can simply query data from controller. In example below I use UserId stored by WebSecurity membership to retrieve account info from database.
public ActionResult AccountInfo()
{
if (FormsAuthentication.CookiesSupported == true && Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
var userId = WebSecurity.CurrentUserId;
var userInfo = context.Users.FirstOrDefault(x => x.UserId == userId);
userInfo.Password = "";
return View(userInfo);
}
else
{
ModelState.AddModelError("", "Wystąpił bląd autoryzacji, zaloguj się jeszcze raz.");
return RedirectToAction("Login", "Account");
}
}
EDIT:
Regarding your edited question as I understand besides the fact that you need to integrate WebSecurity with EF as above (I also forgot to mention that after creating InitializeSimpleMmebershipAttribute class as above you need to decorate your controller with that attribute) you also have problems with implementing generic repository. If that line is a problem:
var allDomains = _db.PrimaryDomains;
Then i suggest to read this article about implementing generic repository:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
If you want thing realy simple all you need is just add to your interface method
GetDomainByUserId(int userId)
and just implement that interface like that:
public class UserDb : DbContext, IUserDataSource
{
public UserDb()
: base("DefaultConnection")
{
}
public DbSet<User> Users { get; set; }
public DbSet<PrimaryDomain> PrimaryDomains { get; set; }
IQueryable<User> IUserDataSource.Users
{
get { return Users; }
}
IQueryable<PrimaryDomain> IUserDataSource.PrimaryDomains
{
get { return PrimaryDomains; }
}
IQueryable<PrimaryDomain> GetDomainByUserId(int userId)
{
return PrimaryDomains.Where(x => x.Id == userId).ToQueryable();
}
void IUserDataSource.Save()
{
SaveChanges();
}
}
But this is very bad approach and I strongly recommend reading that article.

EF Code First: Many-to-many and one-to-many

This is probably just because my knowledge with the EF Code First fluent API is lacking, but I'm stumped.
I want to model the following:
A Groups collection with Id and Name
A Users collection with Id and Name
Each user is assigned to exactly one primary group
Each user may have zero or many secondary groups
The table structure I'm going for would look like:
Groups
Id
Name
Users
Id
Name
PrimaryGroupId
SecondaryGroupAssignments
UserId
GroupId
I've been beating my head against a wall trying to model this with EF Code First, but I can't get it to accept both relationships between User and Group. Sorry for not posting any .NET code (I'm happy to), but it's probably all wrong anyway.
Is there a way to make EF model this? I'm assuming I have to do some sort of configuration with the Fluent API. Maybe a better question is: is there any good, definitive reference for the Fluent API?
Thanks!
Try this (untested):
public class Group
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> PrimaryUsers { get; set; }
public virtual ICollection<User> SecondaryUsers { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int PrimaryGroupId { get; set; }
public virtual Group PrimaryGroup { get; set; }
public virtual ICollection<Group> SecondaryGroups { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Group> Groups { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.HasRequired(u => u.PrimaryGroup)
.WithMany(g => g.PrimaryUsers)
.HasForeignKey(u => u.PrimaryGroupId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<User>()
.HasMany(u => u.SecondaryGroups)
.WithMany(g => g.SecondaryUsers)
.Map(m => m.MapLeftKey("UserId")
.MapRightKey("GroupId")
.ToTable("SecondaryGroupAssignments"));
}
}
Based on Ladislav's excellent answer, here's how to do it without using any mappings - just attributes applied to the Model classes themselves:
public class Group
{
public int Id { get; set; }
[MaxLength(300)]
public string Name { get; set; }
public ICollection<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
[MaxLength(300)]
public string Name { get; set; }
[ForeignKey("PrimaryGroup")]
public int PrimaryGroupId { get; set; }
[Required]
public Group PrimaryGroup { get; set; }
[InverseProperty("Users")]
public ICollection<Group> SecondaryGroups { get; set; }
}
Notes
If you want, you can add the virtual keyword to the 2 ICollections and the Group. This allows lazy-loading. Performance-wise, I don't recommend it, but it is possible.
I included MaxLength attributes with an arbitrary (but safe) length of 300, because putting strings out in EF without a MaxLength gets you low-performance NVarChar(MAX) columns. Totally irrelevant to what's being asked but better to post good code.
I recommend against class names "User" and "Group" for your EF classes. They're going to complicate any SQL you attempt to run later, having to type [User] and [Group] to access them, and complicate using these classes in MVC Controllers where your class User will conflict with the Context property User that gives you access to the Asp.Net Identity library.

Resources