DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • From Naked Objects to Naked Functions
  • Working With Transactions in Entity Framework Core and Entity Developer
  • Working With Lazy Loading and Eager Loading in Entity Framework Core and Entity Developer
  • Strategies for Improving the Performance of Applications Using EF Core

Trending

  • Non-Project Backlog Management for Software Engineering Teams
  • Unlocking the Benefits of a Private API in AWS API Gateway
  • Role of Cloud Architecture in Conversational AI
  • A Complete Guide to Modern AI Developer Tools
  1. DZone
  2. Coding
  3. Frameworks
  4. Entity Framework: new() vs. DbSet.Create()

Entity Framework: new() vs. DbSet.Create()

In Entity, the new and DbSet.Create methods have similar goals with different behaviors. See when to use which one when instantiating new entities.

By 
Tomasz Pęczek user avatar
Tomasz Pęczek
·
Jun. 08, 17 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
10.9K Views

Join the DZone community and get the full member experience.

Join For Free

This is one of those "I had to explain this couple times already so next time, I want something I can redirect people to" kind of post.

What I want to write about is the difference in behavior between using new() and DbSet.Create() for instantiating new entities. In order to do this, I've created a very simple model and context:

public class Planet {
    public virtual int Id {
        get;
        set;
    }
    public virtual string Name {
        get;
        set;
    }
    ...
    public virtual ICollection Natives {
        get;
        set;
    }
}

public class Character {
    public virtual int Id {
        get;
        set;
    }
    public virtual string Name {
        get;
        set;
    }
    ...
    public virtual int HomeworldId {
        get;
        set;
    }
    public virtual Planet Homeworld {
        get;
        set;
    }
}

public interface IStarWarsContext {
    DbSet Planets {
        get;
        set;
    }
    DbSet Characters {
        get;
        set;
    }
    int SaveChanges();
}

public class StarWarsContext: DbContext, IStarWarsContext {
    public DbSet Planets {
        get;
        set;
    }
    public DbSet Characters {
        get;
        set;
    }
}


I've also created a very simple view that lists characters already present in the database and allows for adding new ones.

@using (Html.BeginForm())
{
    <fieldset>
        <legend>New StarWars Character</legend>
        <div>
            @Html.LabelFor(m => m.Name)
        </div>
        <div>
            @Html.TextBoxFor(m => m.Name)
        </div>
        <div>
            @Html.LabelFor(m => m.Homeworld)
        </div>
        <div>
            @Html.DropDownListFor(m => m.Homeworld, Model.Planets)
        </div>
        ...
        <div>
            <input type="submit" value="Add" />
        </div>
    </fieldset>
}
<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Homeworld</th>
            ...
        </tr>
    </thead>
    <tbody>
        @foreach (Character character in Model.Characters)
        {
            <tr>
                <td>@character.Name</td>
                <td>@character.Homeworld.Name</td>
                ...
            </tr>
        }
    </tbody>
</table>


The view is powered by the following ViewModel and controller.

public class StarWarsViewModel {
    public string Name {
        get;
        set;
    }

    ...

    public int Homeworld {
        get;
        set;
    }

    public IEnumerable Planets {
        get;
        set;
    }

    public IReadOnlyList Characters {
        get;
        set;
    }
}

public class StarWarsController: Controller {
    private IStarWarsContext _startWarsContext;

    public StarWarsController(IStarWarsContext startWarsContext) {
        _startWarsContext = startWarsContext;
    }

    [HttpGet]
    public ActionResult Index() {
        return View(GetViewModel());
    }

    [HttpPost]
    public ActionResult Index(StarWarsViewModel viewModel) {
        AddCharacter(viewModel);

        return View(GetViewModel());
    }

    private StarWarsViewModel GetViewModel() {
        return new StarWarsViewModel {
            Planets = _startWarsContext.Planets
                .Select(p => new {
                    p.Id, p.Name
                })
                .ToList()
                .Select(p => new SelectListItem {
                    Value = p.Id.ToString(), Text = p.Name
                }),
                Characters = _startWarsContext.Characters.ToList()
        };
    }

    private void AddCharacter(StarWarsViewModel viewModel) {
        throw new NotImplementedException();
    }
}


The AddCharacter method is the point of interest here. There are two ways to implement it, and they will result in a different behavior.

Creating Entities With new()

Following the first Entity Framework tutorial that pops up on Google will result in code similar to this:

private void AddCharacter(StarWarsViewModel viewModel) {
    Character character = new Character();
    character.Name = viewModel.Name;
    ...
    character.HomeworldId = viewModel.Homeworld;

    _startWarsContext.Characters.Add(character);
    _startWarsContext.SaveChanges();
}


Running this code and adding a new Character will result in a NullReferenceException coming from the part of view that generates the table (to be more exact, it comes from @character.Homeworld.Name). The reason for the exception is the fact that Entity Framework needs to lazy load the Planet entity, but the just-added Character entity is not a dynamic proxy, so lazy loading doesn't work for it. Only Entity Framework can create a dynamic proxy, but in this scenario, there is no way for it to do that — the caller already owns the reference to the entity, and it cannot be changed to a different class.

Creating Entity With DbSet.Create()

In order to be able to create new entities as proper dynamic proxies, the DbSet class provides the Create method. This method returns a new dynamic proxy instance that isn't added or attached to the context. To use it, only a single line of code needs to be changed.

private void AddCharacter(StarWarsViewModel viewModel) {
    Character character = _startWarsContext.Characters.Create();
    character.Name = viewModel.Name;
    ...
    character.HomeworldId = viewModel.Homeworld;

    _startWarsContext.Characters.Add(character);
    _startWarsContext.SaveChanges();
}


After this simple change, the code works as expected — related entities are being lazy loaded when needed.

The Takeaway

The sample above is built in a way that highlights the difference between new() and DbSet.Create() (it even has an N+1 selects hiding in there for the sake of simplicity). In real life, this rarely causes an issue, as there are a couple of other things that can impact the behavior (related entity already present in context or usage of the Include() method, for example). But when this causes an issue, it's always unexpected, and I've seen smart people struggling to wrap their heads around what is going on. It is important to understand the difference and use both mechanisms appropriately (sometimes lack of lazy loading may be desired).

Database Entity Framework Framework

Published at DZone with permission of Tomasz Pęczek. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • From Naked Objects to Naked Functions
  • Working With Transactions in Entity Framework Core and Entity Developer
  • Working With Lazy Loading and Eager Loading in Entity Framework Core and Entity Developer
  • Strategies for Improving the Performance of Applications Using EF Core

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: