I have two class with one-to-many relationship
class Book
{
public int Id {get;set;}
public int AuthorId {get;set;}
public string BookName {get;set;}
}
class Author
{
public int Id {get;set;}
public string AuthorName {get;set;}
public List<Book> Books {get;set;}
}
I want to use AutoFixture to build the list of authors, But I cannot set book.AuthorId related with author.Id
can anyone advise?
Thank you
By default AutoFixture does not know how to correlate types, especially if there is no explicit relationship between them.
The simplest solution would be to create the Author instance first and then using a builder set the AuthorId property.
var fixture = new Fixture();
var author = fixture.Create<Author>();
var book = fixture.Build<Book>()
.With(x => x.AuthorId, author.Id)
.Create();
This however is very verbose and not very helpful when you have to create multiple instances.
A more generic way to instruct AutoFixture, to automatically link the two entities would be to effectively "freeze" a collection of Authors and make each created Book get the AuthorId from an existing (frozen) Author.
You can find the implementation for RandomFromFixedSequence<T> from the following example in this gist.
[Fact]
public void BooksHaveValidAuthorIds()
{
var fixture = new Fixture();
fixture.Customize(new RandomFromFixedSequence<Author>());
fixture.Customize<Book>(c => c
.With<string, Author>(x => x.AuthorId, v => v.Id));
var authorIds = fixture.CreateMany<Author>().Select(x => x.Id);
var book = fixture.Create<Book>();
authorIds.Should().Contain(book.AuthorId);
}
The solution is heavily inspired from Enrico Campidoglio's blog post General-purpose customizations with AutoFixture. Check it out to see how I ended up with that customization implementation.
Related
I am using EF Code First.
I need two tables, LedgerCategories and LedgerSubCategories with a one-to-many relationship (Categories -> SubCategories), with the keys in each being codes (strings) - i.e. LedgerCategoryCode and LedgerSubCategoryCode respectively. However, I need to allow the SubCategoryCode values to be the same for different Categories.
E.g. CategoryCode = REHAB, SubCategoryCodes = MATL, CONTR, and FEES; and CategoryCode = MAINT, SubCategoryCodes = MATL, CONTR, and FEES.
I'm thinking I need to use a composite key and include both the CategoryCode and SubCategoryCode fields in the LedgerSubCategories table. Currently I have:
public class LedgerCategory
{
[Key]
public string LedgerCategoryCode { get; set; }
public string Description { get; set; }
public List<LedgerSubCategory> LedgerSubCategories { get; set; }
}
public class LedgerSubCategory
{
[Key, Column(Order = 0)]
public string LedgerCategoryCode { get; set; }
[Key, Column(Order = 1)]
public string LedgerSubCategoryCode { get; set; }
public string Description { get; set; }
}
I am seeding these tables using only instances of the LedgerCategory class, having each contain a List of appropriately instantiated LedgerSubCategory classes. This appears to both set up the DB schema correctly (in my perception), and populate both tables appropriately.
But, when I reinstantiate a simple List of LedgerCategory, i.e.
using (var db = new BusinessLedgerDBContext())
{
var LedgerCategories = db.LedgerCategories.ToList();
}
The LedgerCategory instances don't contain their respective List of associated LedgerSubCategory instances.
I am trying to avoid, what seems like a kludge, to introduce a unique number or Guid ID field in LedgerSubCategories as a PK and just index off the other Code fields. I haven't tried this, but I'm not sure it would cause any different results for reinstantiating the LedgerCategories and getting associated LedgerSubCategories.
Any advice on how to do this appropriately and get proper results is appreciated.
To, I suppose, answer my own question, I have found that overriding OnModelCreating() in the respective DbContext with Fluent API to establish the one to many relationship and foreign key when the Code First framework establishes the desired DB Schema. There appears no other way to do this, such as with Attributes. By many accounts of others, including MSDN, Fluent API appears to be what is needed. However, that has led me to a new issue, or set of issues, which I've posed as a question here.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configures the one-many relationship between Categories and
// SubCategories, and established the Foreign Key in SubCategories
modelBuilder.Entity<Category>()
.HasMany<SubCategory>(c => c.SubCategories)
.WithRequired(s => s.Category)
.HasForeignKey<string>(s => s.CategoryCode);
}
I'm new to MVC and I am trying to work out how to connect different models to display in a view Example
Model Teams
int TeamID
string Team_Name
Model Players
int PlayerID
string PlayerName
Now I want this information stored in a database so how would I go about linking the two?
So in the Players Model I can use either Team Team or int TeamID
Team_ID I can store in a db table but then have to somehow include the team table when I pull a list of players. or TEAM Team which I can then view the team name by modelItem.team.team_name but cant store a TEAM object in the database.
I know this is basic in terms of MVC but im just struggling to get my head round it.
Any suggestions or links to solutions?
Your entity classes should look something like:
public class Team
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Player> Players { get; set; }
}
public class Player
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("Team")]
public int TeamId { get; set; }
public virtual Team Team { get; set; }
}
With that, with an instance of Player, you can simply do:
player.Team.Name
To get the name of the team. If you have a collection of players you're iterating through, you should eagerly load Team first, so you don't end up with N+1 queries:
var players = db.Players.Include(m => m.Team).ToList();
If you need to go the other way, then, you can load the list of players from an instance of Team as well:
var players = team.Players.ToList();
Likewise, you can eagerly load the players to minimize queries:
var team = db.Teams.Include(m => m.Players).SingleOrDefault(m => m.Id == teamId);
For what it's worth, your class and property names defy conventions. Notice the class and property names in the sample code I provided. An entity class' name should always be singular: Team, not Teams. Property names should be pascal-cased and run together: LikeThis, not likeThis or Like_This. Also, it's an antipattern to include the class name in the property name. The Name property belongs to Team, for example, so of course it's the name of the team. There is zero point in prefixing it with Team (TeamName), and it only makes your code more verbose. For example, which reads better: team.Name or team.TeamName?
Ok I’m at a loss, being new to breeze I’m still learning the ropes. My project uses the hot towel template for AngularJs and breeze from John Papa.
He's what I’m trying to achieve: I have a master\slave tables in my database. An "Agency" has many people it can "Notify". Here are the EF classes for the server side:
public class Agency {
public Agency() {
this.Notifies = new HashSet<Notify>();
}
public long Id { get; set; }
[Required, MaxLength(50)]
public string Name { get; set; }
<<removed unneeded details>>
public bool Active { get; set; }
public virtual ICollection<Notify> Notifies { get; set; }
}
public class Notify
{
public long Id { get; set; }
public long? AgencyId { get; set; }
public string Name { get; set; }
<<removed unneeded details>>
public virtual Agency Agency { get; set; }
}
Now the Maps:
public class AgencyMaps : EntityTypeConfiguration<Agency>
{
internal AgencyMaps()
{
HasKey(x => x.Id);
}
}
public class NotifyMap : EntityTypeConfiguration<Notify>
{
internal NotifyMap()
{
HasKey(x => x.Id);
HasOptional(x => x.Agency)
.WithMany(p => p.Notifies)
.HasForeignKey(i => i.AgencyId);
}
}
Now on the client side I use breeze to create new entities like this:
// create a new entity
function create() {
return manager.createEntity(entityName);
}
// create a new notify entity
function createNotify(){
return manager.createEntity(entityNameNotify);
}
Then there are two scenarios I need to achieve:
- First is where I retrieve an existing agency and add additional
people to notify
- Second is where I create a new agency and add people
to notify
Both fail in the same place.
Note: I’m using SQL server and my Id fields are bigint (long) at this point in time.
I’m retrieving the “Agency” entity and placing it in a variable called “vm.agency”. “vm.agency” has a navigation called “notifies” with an entity type of “Notify”. So when I want to create and add a new person I’m calling this function:
function addNotifyRec(){
if (vm.agency !== undefined){
var notifyRec = datacontext.agency.createNotify(); //<<< fails here
notifyRec.agencyId = vm.agency.id;
notifyRec.name = vm.notify.name;
<<removed unneeded details>>
vm.agency.notifies.push(notifyRec);
logSuccess(“New person to notify added”);
}
else
{ logError(“Agency is undefined”); }
}
As soon as the createNotify() is called I get the “Ids can not be autogenerated for entities with multipart keys” error.
So I’m stuck. It seems to me this is a pretty common scenario. I am obviously not understanding the breeze framework well enough to implement this. If you can point me in the right directions I’d appreciate your help.
UPDATE 4/9/2014
I'm thinking i could eliminate this issue altogether if i switch over to guid id and generate them client side. Is this correct thinking?
What's interesting here is that Breeze thinks that Notify.Id and Notify.AgencyId are multi part primary keys but they are actually not. Id is a PK and AgencyId is an FK. The only thing that I can think of is try removing the EntityTypeConfiguration for both Agency and Notify, specifically the part where it specifies HasKey and HasForeignKey. This Fluent API configuration shouldn't be required as EF will match your configuration by convention instead.
I took a different approach on working around my issue. Since i have the luxury to change out the id types, i swapped out the bigint ids to Uuid types and removed the auto generation of the ids in sql. Now i'm just creating my own ids using breeze.core.getUuid() when a new record is created. Not sure this is the most efficient way to work around the issue, but it seems to be working fine.
I'm writing a small application using ASP.NET MVC just for fun of it, but I have problem grasping how to design one particular variant of one to many relations. Since I'm using LinqToSQL I guess it's more about designing the tables than my C# code, but I'm mentioning it in case the way the data is to be used might affect the design.
The thing I'm having problem with is this:
Let's say I want to make a book database and let's say each book can have multiple names assigned to it (for example translations of the title). One of the titles needs to be the main one.
What seems to be the obvious solution for me, would be to make a table for books and another table for the names. Names get a BookId column and books get a MainNameId column and on top of that foreign keys are set, so when the models are generated in my application, the relations are set correctly off the bat.
However my logic fails as I won't be able to add a book without having a title first and I won't be able to add a title without having related book in the database first. Adding a book to the database was suppose to also add the first (and main title).
Anyway, I can think of a few workarounds for this problem, but I was wondering what's the proper way to solve this.
you have to save both records to 2 tables at the same time.
EntityFramework can do it for you in 1 save changes or you may add first a record to the book table and then to the names table and do "Save changes" for both of them at the same time.
this code should do it:
public class Book
{
public string BookId { get; set; }
public string ISBN { get; set; }
public IEnumerable<BookNames> Names { get; set; }
}
public class BookNames
{
public string BookId { get; set; }
public string BookName { get; set; }
public string Language { get; set; }
}
public class Functions
{
void createBook()
{
Book new_book=new Book();
new_book.ISBN = "RandomISBN";
new_book.Names = new IEnumerable<BookNames>() {
new BookNames{BookName = "The Good Book", Language = "ENG"},
new BookNames{BookName = "El buen libro", Language = "SPN"}
};
dbcontext db = new dbcontext();
db.Books.Add(new_book);
db.SaveChanges();
}
}
This question is similar to Where does business logic sit in MVVM?
However, I didn't want to create a comment chain on that one
Lets say for example that I have a table of invoices and I want to get this data and perform some apportionment on it ready for use in 2 totally separate reports and 3 screens.
In our current web application I would have put this in the Data Service Layer, and all of my reports and screens would have called this
In MVVM people seem to suggest that the model should not be bloated out and that logic should be put in the view models. But in this case I be duplicating the code 5 times?
In his answer to my other question Reed states "Anything that's specific to the domain or business should be reusable by other applications, using other architectures."
Can Reed or someone clarify what my approach should be? Can MVVM be combined with other architectures?
I am using Silverlight 5 with the Simple MVVM Toolkit
Paul
The ViewModel is not for business logic. It is for user interface logic. As its name is given, it is representing the View. If you have five different reports that presents similar data, give this data a name and make all five ViewModels understand how to work with the data objects.
Since we are talking about reports, data is understood to e only displayed. The ViewModel can just be a simple data source with minimal user interface interaction, basically a very thin layer.
I faced the same problem and decided to go this way:
I created classes like controllers in MVC (performing some actions with my model) and I work with them in all ViewModels.
For example: our application has a list of books. We need to add/edit/delete them.
So we have a model:
public class Book {
public int BookId { get; set; }
public string Title { get; set; }
public string Author { get; set; }
}
Then we have a controller class:
public class BookController {
string dbPath = ...;
public void AddBook(string title, string author)
{
var book = new Book() { Title = title, Author = author };
AddBook(book);
}
public void DeleteBook(int id)
{
using (var db = new SQLiteConnection(dbPath))
{
db.Delete<Book>(id);
}
}
public void DeleteBook(Book book)
{
using (var db = new SQLiteConnection(dbPath))
{
DeleteBook(book.BookId);
}
}
public List<Book> GetAllBooks()
{
using (var db = new SQLiteConnection(dbPath))
{
return db.Table<Book>().ToList();
}
}
public Book FindBook(string title, string author, int id)
{
.....
}
}
Now we can use it wherever we need, e.g.:
public class BookListViewModel : ViewModelBase {
public BookListViewModel() {
GetData();
}
void GetData()
{
BookController bc = new BookController(); // here we start using our controller.
_books = new List<Book>();
_books = bc.GetAllBooks();
}
}
Such approach helps us:
1) keep all business logic separately (in controller class)
2) avoid code duplication