ASP.NET MVC3 System.ComponentModel.DataAnnotations and Association - c#

This part of code works fine
[Association(Storage = "profile", ThisKey = "UserId", OtherKey = "UserId")]
public Profile User {
get { return this.profile.Entity; }
set { this.profile.Entity = value; }
}
but if i add in this class
System.ComponentModel.DataAnnotations
then, Association could not be found.
Where is the problem ?

An enhancement to Austin's answer is to employ the using statement:
using L2SAssociation = System.Data.Linq.Mapping.Association;
[L2SAssociation(Storage = "profile", ThisKey = "UserId", OtherKey = "UserId")]
public Profile User
{
get { return this.profile.Entity; }
set { this.profile.Entity = value; }
}

It looks like you've got two namespaces that are conflicting. Try changing Association to System.Data.Linq.Mapping.Association, so it would look like:
[System.Data.Linq.Mapping.Association(Storage = "profile", ThisKey = "UserId", OtherKey = "UserId")]
public Profile User {
get { return this.profile.Entity; }
set { this.profile.Entity = value; }
}

Related

Linq2SQL not inserting related entity

I'm trying to insert into two releated tables with linq2sql but my code only inserts one entity(Email), I dont get any exceptions - just the other entity (attachment) is not inserted.
I think I have an mistake somewhere in the association, but i cant figure out how to set it up properly.
Thanks for help.
Insert code:
using (TransactionScope main_transaction = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(120)))
{
foreach (var attachment in attachmets)
email.Attachments.Add(attachment);
_emails.InsertOnSubmit(email);
_context.SubmitChanges();
main_transaction.Complete();
}
Pocos:
[Table(Name = "maily")]
internal class Email
{
private EntitySet<Attachment> _attachments;
public Email()
{
this._attachments = new EntitySet<Attachment>();
}
[Column(IsPrimaryKey = true, IsDbGenerated = true, Name = "ID_mailu", AutoSync = AutoSync.OnInsert)]
public virtual int ID_mailu { get; set; }
[Association(Storage = "_attachments", OtherKey = "id_mailu")]
public ICollection<Attachment> Attachments
{
get { return _attachments.ToList(); }
set { _attachments.Assign(value); }
}
}
[Table(Name = "MailPrilohy")]
internal class Attachment
{
private EntityRef<Email> _email;
public Attachment()
{
_email = default(EntityRef<Email>);
}
[Column(IsPrimaryKey =true, IsDbGenerated = true, Name = "id_prilohy", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int Id_Prilohy { get; set; }
[Column(Name = "id_mailu", CanBeNull = false, IsDbGenerated = true)]
public int id_mailu { get; set; }
[Association(Storage = "_email", ThisKey = "id_mailu", OtherKey = "ID_mailu", IsForeignKey = true)]
public Email Email
{
get { return _email.Entity; }
set { _email.Entity = value; }
}
}
}
So I have just solved the problem...
The problem was in several places.
1s was the association missed foreign key attribute ..
[Association(Storage = "_email", ThisKey = "id_mailu", OtherKey = "ID_mailu", IsForeignKey = true)]
public Email Email
{
get { return _email.Entity; }
set { _email.Entity = value;}
}
Next, i was supposed to insert attachments -> not the email.
_context.Attachments.InsertAllOnSubmit(attachmets);
Can you try to see if this works for you?
using (TransactionScope main_transaction = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(120)))
{
foreach (var attachment in attachmets)
attachment.Email = email; // only this line changed
_emails.InsertOnSubmit(email);
_context.SubmitChanges();
main_transaction.Complete();
}

MVC Identity 2.0 and managing roles

I have implemented the Identity 2.0 membership and starting to regret it now. But, I'm so deep in this project there is no turning around. My issue is probably simple to most so hopefully I can get some assistance.
I have a grid control in my MVC5 application.
VIEW
#using System.Web.Helpers;
#model List<PTSPortal.Models.PTSUsersViewModel>
#{
var grid = new WebGrid(source: Model, defaultSort: "PropertyName", rowsPerPage: 10);
}
<div id="ContainerBox">
#grid.GetHtml(columns: grid.Columns(
grid.Column("_email", "Email", canSort: true, style: "text-align-center"),
grid.Column("_employeeID", "EmployeeID", canSort: true, style: "text-align-center"),
grid.Column("_phoneNumber", "Phone", canSort: true, style: "text-align-center")
//-----I want to display the user's role here!------
))
</div>
VIEWMODEL
public class PTSUsersViewModel
{
public string _ID { get; set; }
public string _email { get; set; }
public int? _employeeID { get; set; }
public string _phoneNumber { get; set; }
public string _role { get; set; }
}
My goal is to display each registered user's role using the grid.Column just like email, employeeID, and phoneNumber.
CONTROLLER
public ActionResult PTSUsers()
{
List<PTSUsersViewModel> viewModel = FetchInfo().ToList();
return View(viewModel);
}
private static IEnumerable<PTSUsersViewModel> FetchInfo()
{
PTSPortalEntities context = new PTSPortalEntities();
using (ApplicationDbContext _context = new ApplicationDbContext())
{
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(_context));
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(_context));
}
return (from a in context.AspNetUsers
orderby a.Email ascending
select new PTSUsersViewModel
{
_ID = a.Id,
_email = a.Email,
_employeeID = a.EmployeeID,
_phoneNumber = a.PhoneNumber,
//_role = ........
}).ToList<PTSUsersViewModel>();
}
Within my using statement, I have var roleManager and var userManager but they are not doing anything. I was trying to retrieve the user's role, but that's when I stopped and figured I would reach out to SOF for some tips or better approach.
Now, on a side note. There are some service methods already created in the project which work great within other controller methods. Maybe these can be used or modified in my issue above:
public class AppServices
{
// Roles used by this application
public const string AdminRole = "Admin";
public const string TrainerRole = "Trainer";
private static void AddRoles(ref bool DataWasAdded)
{
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
if (roleManager.RoleExists(AdminRole) == false)
{
Guid guid = Guid.NewGuid();
roleManager.Create(new IdentityRole() { Id = guid.ToString(), Name = AdminRole });
DataWasAdded = true;
}
if (roleManager.RoleExists(TrainerRole) == false)
{
Guid guid = Guid.NewGuid();
roleManager.Create(new IdentityRole() { Id = guid.ToString(), Name = TrainerRole });
DataWasAdded = true;
}
}
/// <summary>
/// Checks if a current user is in a specific role.
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
public static bool IsCurrentUserInRole(string role)
{
if (role != null)
{
using (ApplicationDbContext _context = new ApplicationDbContext())
{
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(_context));
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(_context));
if (UserManager.IsInRole(GetCurrentUserID(), role))
{
return true;
}
}
}
return false;
}
/// <summary>
/// Adds a user to a role
/// </summary>
/// <param name="userId"></param>
/// <param name="RoleToPlaceThemIn"></param>
public static void AddUserToRole(string userId, string RoleToPlaceThemIn)
{
// Does it need to be added to the role?
if (RoleToPlaceThemIn != null)
{
using (ApplicationDbContext _context = new ApplicationDbContext())
{
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(_context));
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(_context));
if (UserManager.IsInRole(userId, RoleToPlaceThemIn) == false)
{
UserManager.AddToRole(userId, RoleToPlaceThemIn);
}
}
}
}
Any advice would be appreciated.
Use await UserManager.GetRolesAsync(user) to return list of strings with roles assigned. Because user can have many roles there is no such thing as "user role", there are roles.
So if you'd like to show roles in the table, you'll need to join them into CSV. Something like this:
var roles = await UserManager.GetRoles.Async();
var allUserRoles = String.Join(", ", roles);
_PTSUsersViewModel._roles = allUserRoles;

NullReferenceException on SubmitChanges with Db Generated Properties

I'm at wits end here. The problem is I'm trying to create a new entity in the database, with a db generated identity property, in LINQ to SQL and then create another entity associated with the first one. I'm guessing the problem is that LINQ to SQL cannot insert the second entity without the id from the first entity, which won't be known until the database generates it.
Has anyone else had this problem... if so how did you resolve it? I know I could call SubmitChanges between the creation of the first and the second entity, but this would break the transactional integrity of the program.
Here's a concrete example:
[Table(Name = "Searches")]
public class Search
{
// Db Generated Key
[Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
public Int32 SearchID { get; set; }
// Each search can have multiple search parameters
private EntitySet<SearchParam> searchParams;
[Association(Storage = "searchParams", ThisKey = "SearchID", OtherKey = "SearchID")]
public EntitySet<SearchParam> SearchParams
{
get
{
return searchParams;
}
set
{
searchParams.Assign(value);
}
}
}
[Table(Name = "SearchParams")]
public class SearchParam
{
[Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
public Int32 SearchParamID { get; set; }
[Column]
public String ParamValue { get; set; }
// Each search param is associated with one search
[Column]
public Int32 SearchID { get; set; }
private EntityRef<Search> search = new EntityRef<Search>();
[Association(Storage = "search", ThisKey = "SearchID", OtherKey = "SearchID", IsForeignKey = true)]
public Search Search
{
get
{
return search.Entity;
}
set
{
search.Entity = value;
}
}
}
So with the above code, if I were to do something like the following, .NET gives me a NullReferenceException on SubmitChanges:
using (SampleDataContext context = new SampleDataContext())
{
Search search = new Search();
search.SearchParams.Add(new SearchParam() { ParamValue = "...paramvalue..." });
context.Searches.InsertOnSubmit(search);
context.SubmitChanges();
}
It doesn't look to me like you are initializing the SearchParams list before calling add on it. Does this work:
using (SampleDataContext context = new SampleDataContext()) {
Search search = new Search();
search.SearchParams = new EntitySet<SearchParam>(); //<-- THIS LINE
search.SearchParams.Add(new SearchParam() { ParamValue = "...paramvalue..." });
context.Searches.InsertOnSubmit(search);
context.SubmitChanges();
}
Don't know why yours is not working, but this should work
using (SampleDataContext context = new SampleDataContext())
{
Search search = new Search();
SearchParam param = new SearchParam() { ParamValue = "...paramvalue..." })
param.search = search
context.searchparams.InsertOnSubmit (param ) // Not sure if this is necessary
context.Searches.InsertOnSubmit(search);
context.SubmitChanges();
}
And all in one transaction.
Try adding the following to your Search class
public Search()
{
this.SearchParams = new EntitySet<SearchParams >(
new Action<SearchParams >(this.attach_SearchParams ),
new Action<SearchParams >(this.detach_SearchParams ));
}
private void attach_SearchParams(SearchParams sp)
{
sp.Search = this;
}
private void detach_Search(SearchParams sp)
{
sp.Search = null;
}

linq one to many relationship stores only one member of list

I'm trying to set up a one to many relationship with linq on Windows Phone 8.
My problem is that in the EntitySet<> field only one of the classes which should be stored, really gets stored to the database.
So i made a simple Project to give you clue of my problem.
There are two classes Person and Number. One Person can have many numbers.
Here is the number class:
[Table]
class Number
{
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int NumberID { get; set; }
[Column]
public int PhoneNumber { get; set; }
}
And the Person class:
[Table]
class Person
{
private EntitySet<Number> numbers = new EntitySet<Number>();
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int PersonID { get; set; }
[Column]
public string Name { get; set; }
[Association(Storage = "numbers", ThisKey = "PersonID", OtherKey = "NumberID")]
public EntitySet<Number> Numbers
{
get { return numbers; }
set
{
numbers.Assign(value);
}
}
}
When i now try to insert a person with three numbers:
EntitySet<Number> numbers = new EntitySet<Number>();
DataBase db = new DataBase(App.DBConnectionString);
Number num1 = new Number() { PhoneNumber = 111111 };
Number num2 = new Number() { PhoneNumber = 222222 };
Number num3 = new Number() { PhoneNumber = 333333 };
Person person = new Person() { Name = "Donald" };
numbers.Add(num1);
numbers.Add(num2);
numbers.Add(num3);
person.Numbers = numbers;
try
{
db.Persons.InsertOnSubmit(person);
db.SubmitChanges();
}
catch (Exception s)
{
// do nothing
}
And then try to retrieve the data again:
DataBase db = new DataBase(App.DBConnectionString);
string text = "";
foreach (Person person in db.Persons)
{
foreach (Number num in person.Numbers)
{
text += num.PhoneNumber + System.Environment.NewLine;
}
}
TextBlock.Text = text;
i only get the first phone number which is '111111'. Interesting is, that on the second run the text string holds '111111' and '222222'. This is because in the second Person the second phone number is saved and in the third person the third phone number and so on.
So if you do that often enough you get:
111111
222222
333333
111111
222222
333333
...
Btw if you jump with the debugger to 'db.Persons.InsertOnSubmit(person);' and look into 'person' there is a list with all three numbers in it. So it should work...
I tried really hard, but i can't figure out a way to get it right. My suspicion though is on the [Association] attribute.
Here is a link to the source so you can get the whole picture if you want: https://docs.google.com/file/d/0B5G4zya_BlZyUlU0azVvbVdiajA/edit?usp=sharing
I also had that problem a while ago. I added a few lines to my code that made it disappear.
Linq2SQL is a bit magical and sometimes things (don't) work for no obvious reason. Just to be perfectly sure you might want to implement the official One-To-Many solution provided by Microsoft:
http://msdn.microsoft.com/en-us/library/vstudio/bb386950(v=vs.100).aspx
Also I would make the following adjustments:
[Table]
class Number
{
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int NumberID { get; set; }
[Column]
public int _personID { get; set; }
[Column]
public int PhoneNumber { get; set; }
private EntityRef<Person> _person;
[Association(Storage = "_person", ThisKey = "_personID", OtherKey = "PersonID", IsForeignKey = true)]
public Person Person
{
get { return this._person.Entity; }
set {
this._person.Entity = value;
if (value != null)
{
this._personID = value.PersonID;
}
}
}
}
And I'd add this to the constructor:
public Person()
{
this._numbers = new EntitySet<Number>(
delegate (Number entity)
{
entity.Person = this;
},
delegate (Number entity)
{
entity.Person = null;
});
}
As a test I would not try to load the entire object. First just check if all numbers have made it to the database:
var numbers = db.Numbers.ToList();
This is because L2S on Windows Phone has serious trouble reading deep object connections. One level is fine but deeper relationships are ignored. So if your Person class resides in another class that could be a problem as well.
Edit: You can add options to your DB context in order to force deep object loading:
_db = new DBContext("isostore:/mydb.sdf");
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Person>(p => p.Numbers);
_db.LoadOptions = loadOptions;

How to create entity with nested via LINQ to SQL

I got one entity linked with another:
[Table(Name = "Employees")]
public sealed class Employee
{
[Column(Name = "Id", UpdateCheck = UpdateCheck.Never, IsPrimaryKey = true, IsDbGenerated = true, DbType = "Int NOT NULL IDENTITY")]
public int Id { get; set; }
[Column(Name = "Phone", UpdateCheck = UpdateCheck.Never, DbType = "Char(20)")]
public string Phone { get; set; }
[Column(Name = "UserId", UpdateCheck = UpdateCheck.Never, DbType = "Int NOT NULL")]
public int UserId { get; set; }
[Association(Storage = "_user", ThisKey = "UserId")]
public User User
{
get { return _user.Entity; }
set { _user.Entity = value; }
}
private EntityRef<User> _user;
}
[Table(Name = "Users")]
public sealed class User
{
[Column(Name = "Id", UpdateCheck = UpdateCheck.Never, IsPrimaryKey = true, IsDbGenerated = true, DbType = "Int NOT NULL IDENTITY")]
public int Id { get; set; }
[Column(Name = "LastName", UpdateCheck = UpdateCheck.Never, DbType = "NVarChar(100)")]
public string LastName { get; set; }
[Column(Name = "FirstName", UpdateCheck = UpdateCheck.Never, DbType = "NVarChar(100)")]
public string FirstName { get; set; }
}
Then I want to create an employee:
var entity = new Employee
{
Phone = "Some",
User = new User
{
FirstName = "Some",
LastName = "Some"
}
};
context.GetTable<Employee>().InsertOnSubmit(entity);
context.SubmitChanges();
And got this:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Employees_Users"
Is it posible to create linked entities in LINQ to SQL?
Try specifying the OtherKey property of the AssociationAttribute as well. If not specified, it will default to the key of the related class, but in your case the names of the keys in the different classes are different (UserId vs Id).
[Association(Storage = "_user", ThisKey = "UserId", OtherKey="Id")]
public User User
{
get { return _user.Entity; }
set { _user.Entity = value; }
}
private EntityRef<User> _user;

Categories

Resources