I'm trying to write a LINQ statement for EF Core 2 that only requests SQL return two columns: UserID and FirstNamePreferred.
Everything I've tried creates a SQL statement that requests all columns.
Here is my code:
var model = db.FamilyMember
.Where(fm => fm.UserID == message.CurrentUserID)
.Select(fm => new Model
{
UserID = message.CurrentUserID,
FirstNamePreferred = fm.FirstNamePreferred
})
.AsNoTracking()
.FirstOrDefault();
My view model:
public class Model
{
public string UserID { get; set; }
public string FirstNamePreferred { get; set; }
}
This generates the following SQL via Profiler:
exec sp_executesql N'SELECT TOP(1) [fm].[ID], [fm].[DOB], [fm].[DOD], [fm].[EyeColourID], [fm].[FamilyID], [fm].[FirstName], [fm].[FirstNameKnownAs], [fm].[Gender], [fm].[HairColour], [fm].[IdentifiesAs], [fm].[LastName], [fm].[MiddleNames], [fm].[NickName], [fm].[PictureExt], [fm].[PictureUID], [fm].[PrimaryEmailAddress], [fm].[SkinTone], [fm].[UserID]
FROM [FamilyMember] AS [fm]
WHERE [fm].[UserID] = #__message_CurrentUserID_0',N'#__message_CurrentUserID_0 nvarchar(450)',#__message_CurrentUserID_0=N'b0e1fe4c-f218-4903-8117-465a68cd99fc'
Update: The issue was that FirstNamePreferred was not actually a database field. Sorry I didn't drill down this far in the code, rookie mistake.
public string FirstNamePreferred
{
get
{
if (FirstNameKnownAs == null)
{
return FirstName;
}
else
{
return FirstNameKnownAs;
}
}
}
Update: The issue was that FirstNamePreferred was not actually a database field. Sorry I didn't drill down this far in the code, rookie mistake.
public string FirstNamePreferred
{
get
{
if (FirstNameKnownAs == null)
{
return FirstName;
}
else
{
return FirstNameKnownAs;
}
}
}
This will work:
var model = db.FamilyMember
.Where(fm => fm.UserID == message.CurrentUserID)
.Select(fm => new
{
UserID = message.CurrentUserID,
FirstNamePreferred = fm.FirstNamePreferred
})
.AsNoTracking()
.FirstOrDefault();
Using a DTO that is not part of your DbContext will cause SELECT *
Related
I'm using EF 4.3.1 and I'm doing my first implementation of Code First and testing the data. Here's my setup trying to implement eager loading.
public class Model
{
public int Id { get; set; }
public ICollection<ModelArchive> ModelArchives { get; set; }
}
public class ModelArchive
{
public int Id { get; set; }
public ICollection<Option> Options { get; set; }
}
public class Option
{
public int Id { get; set; }
public bool Deleted { get; set; }
}
I'd like to be able to only select the Options where Deleted == false in my query. So far I'm coming up empty or it results in an exception when running the query.
Here's my current query:
using (var db = new ModelContainer())
{
db.Configuration.LazyLoadingEnabled = false;
var model = db.Models.Where(m => m.Id == 3)
.Include(m => m.ModelArchives.Select(o => o.Option).Where(o => o.Deleted == false));
}
Exception: Message = "The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.\r\nParameter name: path"
Any help would be appreciated.
You can't load filtered data with Entity Framework. Navigation properties either contain all related entities, or none of them.
Consider to do manual join and return anonymous objects with not deleted options.
You can try
using (var db = new ModelContainer())
{
//db.Configuration.LazyLoadingEnabled = false;
var model = db.Models.Where(m => m.Id == 3 && m.ModelArchives.Option.Deleted==false)
.Include(m => m.ModelArchives.Option);
}
You can use generic function to get the data
public List<T> IncludeMultipleWithWhere(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includes)
{
IQueryable<T> itemWithIncludes = dbContext.Set<T>() as IQueryable<T>;
try
{
if (includes != null)
{
itemWithIncludes = includes.Aggregate(itemWithIncludes,
(current, include) => current.Include(include)).Where(predicate);
}
}
catch (Exception ex)
{
}
finally { }
return itemWithIncludes.ToList();
}
your calling function just need to passing the parameter like
Expression<Func<Models, bool>> whereCond1 = (m) => m.Id == 3 && m.ModelArchives.Option.Deleted==false;
Expression<Func<Models, object>>[] includeMulti = { m => m.ModelArchives.Option };
You were correct in disabling lazyloading.
But then you have to filter the navigation property in a subquery, and EF will magically attach it to your main query. Here is something that should work
using (var db = new ModelContainer())
{
db.Configuration.LazyLoadingEnabled = false;
var filteredModelArchives = db.ModelArchives.Select(o => o.Option).Where(o => o.Deleted == false).Include("Options");
var model = db.Models.Where(m => m.Id == 3);
}
What programmers needed was a way to generalize different data systems
in a standard, consistent, and powerful way. In the world of .NET
application development, Microsoft ADO.NET meets that need. Instead of
worrying about the minutiae associated with the different database
systems, programmers using ADO.NET focus on the data content itself.
From the book "ADO.NET 4 Step by Step"
Always thinking the next structure.
ADO.NET can be sepearated on two parts:
1. Classic ADO.NET (DataSets, DataTables, etc.). In classic variant there are distinct DB connection providers, every which translates DB internal data to the .NET. For example MS SQL Server holds data in one way and Oracle in another. So we can change the data base with changing provider.
Seems as magic pill, however all ADO.NET statements are hard coded.
For MS SQL top 10 select statement is SELECT TOP 10 ROWS FROM TABLE, and for Oracle SELECT ROWS FROM TABELE WHERE ROWNUM <= 10. It seems that changing DB and provider will not help, isnt' it?
2. Entity Framework. This framework has internal independent language statements that is transformed to the choosen DB statesment, which looks as truely magic pill:
LINQ -> Internal EF statement -> MS SQL DB,
LINQ -> Internal EF statement -> Oracle DB.
So can one simply change the DB and be almost independent from DB in classic ADO.NET?
So can one simply change the DB and be almost independent from DB in classic ADO.NET?
Of course you can, but to be able to do that we have to debunk this statement.
Seems as magic pill, however all ADO.NET statements are hard coded.
That's not a byproduct of ADO.NET - that's a byproduct of your architecture. You're building the SQL statements in the wrong place. You need concrete, provider specific models, that are capable of building statements that differ between providers. This isn't as bad as it sounds - most statements can be auto-generated leveraging reflection - it's just the special cases.
For example, let's say I had a model like this:
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
and let's say I wanted to generate a SELECT statement out of that. Well, I'm going to first need a couple attributes to tell me what property is the PK and what properties are data fields:
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
internal sealed class DataFieldAttribute : Attribute
{
public DataFieldAttribute()
{
}
}
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
sealed class PrimaryKeyAttribute : Attribute
{
public PrimaryKeyAttribute()
{
}
}
and now I need to decorate that class:
public class Employee
{
[PrimaryKey]
public int ID { get; set; }
[DataField]
public string Name { get; set; }
[DataField]
public DateTime DateOfBirth { get; set; }
}
and now I just need a simple process to create a SELECT statement, so first let's build a base data model class:
public abstract class DataModelBase
{
protected string _primaryKeyField;
protected List<string> _props = new List<string>();
public DataModelBase()
{
PropertyInfo pkProp = this.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(PrimaryKeyAttribute), false).Length > 0).FirstOrDefault();
if (pkProp != null)
{
_primaryKeyField = pkProp.Name;
}
foreach (PropertyInfo prop in this.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(DataFieldAttribute), false).Length > 0))
{
_props.Add(prop.Name);
}
}
public virtual string TableName { get { return this.GetType().Name; } }
public virtual string InsertStatement
{
get
{
return string.Format("INSERT INTO [{0}] ({1}) VALUES ({2})",
this.TableName,
GetDelimitedSafeFieldList(", "),
GetDelimitedSafeParamList(", "));
}
}
public virtual string UpdateStatement
{
get
{
return string.Format("UPDATE [{0}] SET {1} WHERE [{2}] = #{2}",
this.TableName,
GetDelimitedSafeSetList(", "),
_primaryKeyField);
}
}
public virtual string DeleteStatement
{
get
{
return string.Format("DELETE [{0}] WHERE [{1}] = #{1}",
this.TableName,
_primaryKeyField);
}
}
public virtual string SelectStatement
{
get
{
return string.Format("SELECT [{0}], {1} FROM [{2}]",
_primaryKeyField,
GetDelimitedSafeFieldList(", "),
this.TableName);
}
}
protected string GetDelimitedSafeParamList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("#{0}", k)));
}
protected string GetDelimitedSafeFieldList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("[{0}]", k)));
}
protected string GetDelimitedSafeSetList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("[{0}] = #{0}", k)));
}
}
and now let's inherit from that data model:
public class Employee : DataModelBase
and boom, now I can get those statements any time I need them, and those statements work for any concrete provider right now.
And then I'll use Dapper to get the data because it leverages the IDbConnection interface like what you need and it's ridiculously fast - and there you go - a provider independent solution that would easily be extended to build an Oracle version of Employee if necessary.
This framework has internal independent language statements that is transformed to the choosen DB statesment, which looks as truely magic pill
Sure, it may look like a magic pill, but it's really a curse in a lot of ways. You have no flexibility (at least it's not easy) to build statements that are optimized for your needs to support high transaction and volume databases. You truly are subject to the master here. The .NET Entity Framework builds those statements for you, and I can't even count how many questions on StackOverflow have been over how can I change the SQL that's being generated by this LINQ statement leveraging the .NET Entity Framework.
was staring to play with this. I know this is a old post. thanks to the above example herewith little modified. Still lots to be done
using System.Collections.Generic;
using System.Reflection;
using Dapper;
using System.Linq;
using AppAttributes;
using System.ComponentModel.DataAnnotations;
using System;
public abstract class DataModelBase
{
protected string _primaryKeyField;
protected List<string> _props = new List<string>();
protected List<BuildClass> _class = new List<BuildClass>();
public DataModelBase()
{
PropertyInfo pkProp = this.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Length > 0).FirstOrDefault();
if (pkProp != null)
{
_primaryKeyField = pkProp.Name;
}
foreach (PropertyInfo prop in this.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(DataFieldAttribute), false).Length > 0))
{
_props.Add(prop.Name);
}
foreach(PropertyInfo prop in this.GetType().GetProperties())
{
if(prop.GetCustomAttributes<ExcludeAttribute>().Count<ExcludeAttribute>() > 0) continue;
MaxLengthAttribute maxLength = prop.GetCustomAttribute<MaxLengthAttribute>();
MinLengthAttribute minLength = prop.GetCustomAttribute< MinLengthAttribute>();
StringLengthAttribute stringLength = prop.GetCustomAttribute< StringLengthAttribute>();
RequiredAttribute required = prop.GetCustomAttribute<RequiredAttribute>();
RangeAttribute range = prop.GetCustomAttribute<RangeAttribute>();
DataTypeAttribute dataType = prop.GetCustomAttribute<DataTypeAttribute>();
KeyAttribute key = prop.GetCustomAttribute<KeyAttribute>();
var kyk = prop.PropertyType;
//var sss = kyk.FullName.;
var cl = new BuildClass
{
Name = prop.Name,
MaxLength = maxLength != null
? (int?)maxLength.Length
: stringLength != null
? (int?)stringLength.MaximumLength : null,
MinLength = minLength != null
? (int?)minLength.Length
: stringLength != null
? (int?)stringLength.MinimumLength : null,
PrimaryKey = key != null ? true : false,
Type = prop.PropertyType.Name.ToString()
};
_class.Add(cl);
}
}
[Exclude]
public virtual string TableName { get { return this.GetType().Name; } }
[Exclude]
public virtual string InsertStatement
{
get {
return string.Format("INSERT INTO [{0}] ({1}) VALUES ({2})",
this.TableName,
GetDelimitedSafeFieldList(", "),
GetDelimitedSafeParamList(", "));
}
}
[Exclude]
public virtual string UpdateStatement
{
get {
return string.Format("UPDATE [{0}] SET {1} WHERE [{2}] = #{2}",
this.TableName,
GetDelimitedSafeSetList(", "),
_primaryKeyField);
}
}
[Exclude]
public virtual string DeleteStatement
{
get {
return string.Format("DELETE [{0}] WHERE [{1}] = #{1}",
this.TableName,
_primaryKeyField);
}
}
[Exclude]
public virtual string SelectStatement
{
get {
return string.Format("SELECT [{0}], {1} FROM [{2}]",
_primaryKeyField,
GetDelimitedSafeFieldList(", "),
this.TableName);
}
}
[Exclude]
public virtual string CreateStatement
{
get {
return "CREATE TABLE " + TableName+" (" + GetDelimetedCreateParamList(",")
+ ", CONSTRAINT PK_"
+ _class.Where(c=>c.PrimaryKey).FirstOrDefault().Name
+ " PRIMARY KEY("
+ string.Join(",", _class.Where(c=>c.PrimaryKey).Select(c=>c.Name)) + ") )";
}
}
protected string GetDelimetedCreateParamList(string delimeter)
{
return string.Join(delimeter, _class.Select(k => string.Format(" {0} {1} ({2}) {3}" + Environment.NewLine,
k.Name,
GetSqlType(k.Type),
k.MaxLength,
k.NotNull == true || k.PrimaryKey == true ? "NOT NULL " : ""
//k.PrimaryKey == true ? "PRIMARY KEY" : ""
).Replace("()", ""))
);
}
protected string GetSqlType(string type)
{
switch(type.ToUpper())
{
case "INT16":
return "smallint";
case "INT16?":
return "smallint";
case "INT32":
return "int";
case "INT32?":
return "int";
case "INT64":
return "bigint";
case "INT64?":
return "bigint";
case "STRING":
return "NVARCHAR";
case "XML":
return "Xml";
case "BYTE":
return "binary";
case "BYTE?":
return "binary";
case "BYTE[]":
return "varbinary";
case "GUID":
return "uniqueidentifier";
case "GUID?":
return "uniqueidentifier";
case "TIMESPAN":
return "time";
case "TIMESPAN?":
return "time";
case "DECIMAL":
return "money";
case "DECIMAL?":
return "money";
case "bool":
return "bit";
case "bool?":
return "but";
case "DateTime":
return "datetime";
case "datetime?":
return "datetime";
case "double":
return "float";
case "double?":
return "float";
case "char[]":
return "nchar";
}
return "UNKNOWN";
}
private string CreateField(BuildClass column)
{
return " " + column.Name + " " + column.Type + " (" + column.MaxLength + ") ";
}
protected string GetDelimitedSafeParamList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("#{0}", k)));
}
protected string GetDelimitedSafeFieldList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("[{0}]", k)));
}
protected string GetDelimitedSafeSetList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("[{0}] = #{0}", k)));
}
}
public class BuildClass
{
public string Name { get; set; }
public string Type { get; set; }
public bool PrimaryKey { get; set; }
//public bool ForeignKey { get; set; }
public int? MinLength { get; set; }
public int? MaxLength { get; set; }
public bool NotNull { get; set; } = false;
}
Trying to make use of System.Web.Http.OData.Delta to implement PATCH methods in ASP.NET Web API services, but it seems unable to apply changes to properties of type IEnumerable<T>. I'm using the latest Git revision of Delta (2012.2-rc-76-g8a73abe). Has anyone been able to make this work?
Consider this data type, which it should be possible to update in a PATCH request to the Web API service:
public class Person
{
HashSet<int> _friends = new HashSet<int>();
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IEnumerable<int> Friends
{
get { return _friends; }
set
{
_friends = value != null ? new HashSet<int>(value) : new HashSet<int>();
}
}
public Person(int id, string firstName, string lastName)
{
Id = id;
FirstName = firstName;
LastName = lastName;
}
public Person()
{
}
}
This Web API method implements patching of a Person through Delta<Person>:
public void Patch(int id, Delta<Person> delta)
{
var person = _persons.Single(p => p.Id == id);
delta.Patch(person);
}
If I send a PATCH request with the following JSON to the service, the person's Friends property should be updated, but alas it doesn't happen:
{"Friends": [1]}
The crux of the matter is really how to make Delta update Friends with this data. See also the discussion at CodePlex.
The problem likely is that Deta will try to assign JSON's JArray to your Hashset<int>
If you are using it against JsonMEdiaTypeFormatter and you internalized the Delta code (meaning you can modify it), you'd have to do something like this (this is rough, but works):
Inside, bool TrySetPropertyValue(string name, object value) of Delta<T>, where it returns false:
if (value != null && !cacheHit.Property.PropertyType.IsPrimitive && !isGuid && !cacheHit.Property.PropertyType.IsAssignableFrom(value.GetType()))
{
return false;
}
Change to:
var valueType = value.GetType();
var propertyType = cacheHit.Property.PropertyType;
if (value != null && !propertyType.IsPrimitive && !propertyType.IsAssignableFrom(valueType))
{
var array = value as JArray;
if (array == null)
return false;
var underlyingType = propertyType.GetGenericArguments().FirstOrDefault() ??
propertyType.GetElementType();
if (underlyingType == typeof(string))
{
var a = array.ToObject<IEnumerable<string>>();
value = Activator.CreateInstance(propertyType, a);
}
else if (underlyingType == typeof(int))
{
var a = array.ToObject<IEnumerable<int>>();
value = Activator.CreateInstance(propertyType, a);
}
else
return false;
}
This will only work with collections of int or string but hopefully nudges you into a good direction.
For example, now your model can have:
public class Team {
public HashSet<string> PlayerIds { get; set; }
public List<int> CoachIds { get; set; }
}
And you'd be able to successfully update them.
You could override the TrySetPropertyValue method of the Delta class and make use of JArray class:
public sealed class DeltaWithCollectionsSupport<T> : Delta<T> where T : class
{
public override bool TrySetPropertyValue(string name, object value)
{
var propertyInfo = typeof(T).GetProperty(name);
return propertyInfo != null && value is JArray array
? base.TrySetPropertyValue(name, array.ToObject(propertyInfo.PropertyType))
: base.TrySetPropertyValue(name, value);
}
}
If you are using the ODataMediaTypeFormatter, this should be working. There are a couple of caveats to mention though.
1) your collections have to be settable.
2) the entire collection is replaced. you cannot remove/add individual elements.
Also, there is an issue tracking item 1 - '670 -Delta should support non-settable collections.'
class DemoUser
{
[TitleCase]
public string FirstName { get; set; }
[TitleCase]
public string LastName { get; set; }
[UpperCase]
public string Salutation { get; set; }
[LowerCase]
public string Email { get; set; }
}
Suppose i have demo-class as written above, i want to create some custom annotations like LowerCase,UpperCase etc so that its value gets converted automatically. Doing this will enable me to use these annotations in other classes too.
As Ladislav implied, this is two questions in one.
Assuming you follow the recipe for creating attributes in Jefim's link, and assuming you're calling those created attribute classes "UpperCaseAttribute", "LowerCaseAttribute", and "TitleCaseAttribute", the following SaveChanges() override should work in EF 4.3 (the current version as of the time of this answer post).
public override int SaveChanges()
{
IEnumerable<DbEntityEntry> changedEntities = ChangeTracker.Entries().Where(e => e.State == System.Data.EntityState.Added || e.State == System.Data.EntityState.Modified);
TextInfo textInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
changedEntities.ToList().ForEach(entry =>
{
var properties = from attributedProperty in entry.Entity.GetType().GetProperties()
where attributedProperty.PropertyType == typeof (string)
select new { entry, attributedProperty,
attributes = attributedProperty.GetCustomAttributes(true)
.Where(attribute => attribute is UpperCaseAttribute || attribute is LowerCaseAttribute || attribute is TitleCaseAttribute)
};
properties = properties.Where(p => p.attributes.Count() > 1);
properties.ToList().ForEach(p =>
{
p.attributes.ToList().ForEach(att =>
{
if (att is UpperCaseAttribute)
{
p.entry.CurrentValues[p.attributedProperty.Name] = textInfo.ToUpper(((string)p.entry.CurrentValues[p.attributedProperty.Name]));
}
if (att is LowerCaseAttribute)
{
p.entry.CurrentValues[p.attributedProperty.Name] = textInfo.ToLower(((string)p.entry.CurrentValues[p.attributedProperty.Name]));
}
if (att is TitleCaseAttribute)
{
p.entry.CurrentValues[p.attributedProperty.Name] = textInfo.ToTitleCase(((string)p.entry.CurrentValues[p.attributedProperty.Name]));
}
});
});
});
return base.SaveChanges();
}
You can override the SaveChanges method in your EF context (if you use default code-generation just write a partial class). Something like the following:
public partial class MyEntityContext
{
public override int SaveChanges(SaveOptions options)
{
IEnumerable<ObjectStateEntry> changedEntities =
this.ObjectStateManager.GetObjectStateEntries(
System.Data.EntityState.Added | System.Data.EntityState.Modified);
// here you can loop over your added/changed entities and
// process the custom attributes that you have
return base.SaveChanges(options);
}
}
I have created a partial class of an entity for getting a foreign key property on it.
public partial class Artikel
{
public int WarengruppenID
{
get
{
if (WarengruppeReference.EntityKey == null) return 0;
return (int)WarengruppeReference.EntityKey.EntityKeyValues[0].Value;
}
set
{
WarengruppeReference.EntityKey =
new EntityKey("ConsumerProtectionEntities.Warengruppe", "WarengruppenID", value);
}
}
}
Now I change the foreign key (property) but nothing happens?!
What do I have to do to update a foreign key for an entity?
I use EF 3.5 SP1 in ASP.NET MVC 2
EDIT
id = ArtikelID
updatedArtikel = Artikel properties
ArtikelWarengruppen = selected DropDownList value
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, Artikel updatedArtikel, string ArtikelWarengruppen)
{
try
{
int artikelWarengruppenID = int.Parse(ArtikelWarengruppen);
var originalArtikel = (from art in _db.Artikel.Include(typeof(Warengruppe).Name)
where art.ArtikelID == id
select art).FirstOrDefault();
_db.Attach(originalArtikel);
updatedArtikel.ArtikelID = id;
// Update FK
updatedArtikel.WarengruppenID = artikelWarengruppenID;
_db.ApplyPropertyChanges(typeof(Artikel).Name, updatedArtikel);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I've solved the problem.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, Artikel updatedArtikel, string ArtikelWarengruppen)
{
try
{
// update foreign key
int artikelWarengruppenID = int.Parse(ArtikelWarengruppen);
var originalArtikel = (from art in _db.Artikel.Include(typeof(Warengruppe).Name)
where art.ArtikelID == id
select art).FirstOrDefault();
originalArtikel.WarengruppenID = artikelWarengruppenID;
_db.Attach(originalArtikel);
// update properties
updatedArtikel.ArtikelID = id;
_db.ApplyPropertyChanges(typeof(Artikel).Name, updatedArtikel);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
But is there a better way?
This should be the optimal way to achieve what you want:
int artikelWarengruppenID = int.Parse(ArtikelWarengruppen);
updatedArtikel.WarengruppenID = artikelWarengruppenID;
updatedArtikel.ArtikelID = id;
_db.Entry(updatedArtikel).State = EntityState.Modified;
_db.SaveChanges();
This does assume that your posted Artikel contains all the data that you want to keep in the entity.