Сохранить твиты с Entity Framework

1

Я пытаюсь сохранить сообщения о статусе с Entity Framework, но имею проблему, что каждый раз, когда я пытаюсь сохранить твитер от пользователя, который уже существует в базе данных, я получаю исключение!

{"A duplicate value cannot be inserted into a unique index. [ Table name = users,Constraint name = PK_dbo.users ]"}

Я полностью понимаю, почему я получаю эту ошибку, но понятия не имею, как ее предотвратить!

Чтобы сохранить сообщения о состоянии, выполните следующие действия.

Версия 1:

db.status.Add(status);
db.SaveChanges();

Каждое сообщение состояния содержит полную информацию о пользователе как суб-сущность. Я использую Model (status.cs & user.cs) этого фрагмента кода: https://github.com/swhitley/TwitterStreamClient


С информацией из этого вопроса: Сохранить отдельный объект в Entity Framework 6 Я придумал эту идею:

Версия 2:

user usr = db.user.Where<user>(u => u.id == status.user.id).SingleOrDefault();
if (usr == null)
    db.user.Add(status.user);
else
{
    db.user.Attach(status.user);
    db.Entry(status.user).State = EntityState.Modified;
} 

db.status.Add(status);
db.SaveChanges();

Но это приведет к следующему сообщению об ошибке:

Прикрепление объекта типа "TwitterStreamClient.user" не удалось, потому что другой объект того же типа уже имеет такое же значение первичного ключа. Это может произойти при использовании метода "Прикрепить" или установки состояния объекта в "Без изменений" или "Модифицировано", если любые объекты на графике имеют конфликтующие значения ключей. Это может быть связано с тем, что некоторые объекты являются новыми и еще не получили значения ключей базы данных. В этом случае используйте метод "Добавить" или "Добавленное" состояние объекта для отслеживания графика, а затем, если необходимо, установите состояние не новых объектов "Без изменений" или "Модифицировано".


И в соответствии с просьбой здесь приведены мои статусные и пользовательские классы:

user.cs:

using System;
using System.Globalization;
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;

namespace TwitterStreamClient
{
    [DataContract]
    public class user
    {
        //<user>
        //<id>1401881</id>
        // <name>Doug Williams</name>
        // <screen_name>dougw</screen_name>
        // <location>San Francisco, CA</location>
        // <description>Twitter API Support. Internet, greed, users, dougw and opportunities are my passions.</description>
        // <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/59648642/avatar_normal.png</profile_image_url>
        // <url>http://www.igudo.com</url>
        // <lang>en</lang>
        // <protected>false</protected>
        // <followers_count>1027</followers_count>
        // <profile_background_color>9ae4e8</profile_background_color>
        // <profile_text_color>000000</profile_text_color>
        // <profile_link_color>0000ff</profile_link_color>
        // <profile_sidebar_fill_color>e0ff92</profile_sidebar_fill_color>
        // <profile_sidebar_border_color>87bc44</profile_sidebar_border_color>
        // <friends_count>293</friends_count>
        // <created_at>Sun Mar 18 06:42:26 +0000 2007</created_at>
        // <favourites_count>0</favourites_count>
        // <utc_offset>-18000</utc_offset>
        // <time_zone>Eastern Time (US & Canada)</time_zone>
        // <profile_background_image_url>http://s3.amazonaws.com/twitter_production/profile_background_images/2752608/twitter_bg_grass.jpg</profile_background_image_url>
        // <profile_background_tile>false</profile_background_tile>
        // <statuses_count>3390</statuses_count>
        // <notifications>false</notifications>
        // <following>false</following>
        // <verified>true</verified>
        // <contributors_enabled>false</verified>
        //</user> 

        [DataMember]
        [Key]
        public string id { get; set; }
        [DataMember]
        public string name { get; set; }
        [DataMember]
        public string screen_name { get; set; }
        [DataMember]
        public string location { get; set; }
        [DataMember]
        public string description { get; set; }
        [DataMember]
        public string profile_image_url { get; set; }
        [DataMember]
        public string url { get; set; }
        [DataMember]
        public string lang { get; set; }
        [DataMember]
        public string @protected { get; set; }
        [DataMember]
        public string followers_count { get; set; }
        [DataMember]
        public string profile_background_color { get; set; }
        [DataMember]
        public string profile_text_color { get; set; }
        [DataMember]
        public string profile_link_color { get; set; }
        [DataMember]
        public string profile_sidebar_fill_color { get; set; }
        [DataMember]
        public string profile_sidebar_border_color { get; set; }
        [DataMember]
        public string friends_count { get; set; }
        //save date only as string for now as DateTimeOffset is not supported
        //public DateTimeOffset created_at_dt { get; set; }
        [DataMember]
        public string created_at
        {
            get ; //{ return created_at_dt.ToString("ddd MMM dd HH:mm:ss zzz yyyy"); }
            set;  //{ created_at_dt = DateTimeOffset.ParseExact(value, "ddd MMM dd HH:mm:ss zzz yyyy", CultureInfo.InvariantCulture);           }
        }
        [DataMember]
        public string favourites_count { get; set; }
        [DataMember]
        public string utc_offset { get; set; }
        [DataMember]
        public string time_zone { get; set; }
        [DataMember]
        public string profile_background_image_url { get; set; }
        [DataMember]
        public string profile_background_tile { get; set; }
        [DataMember]
        public string statuses_count { get; set; }
        [DataMember]
        public string notifications { get; set; }
        [DataMember]
        public string following { get; set; }
        [DataMember]
        public string verified { get; set; }
        [DataMember]
        public string contributors_enabled { get; set; }
    }
}

status.cs

using System;
using System.Runtime.Serialization;
using System.Globalization;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace TwitterStreamClient
{
    //<status>
    //<created_at>Tue Apr 07 22:52:51 +0000 2009</created_at>
    //<id>1472669360</id>
    //<text>At least I can get your humor through tweets. RT @abdur: I don't mean this in a bad way, but genetically speaking your a cul-de-sac.</text>
    //<source><a href="http://www.tweetdeck.com/">TweetDeck</a></source>
    //<truncated>false</truncated>
    //<in_reply_to_status_id></in_reply_to_status_id>
    //<in_reply_to_user_id></in_reply_to_user_id>
    //<favorited>false</favorited>
    //<in_reply_to_screen_name></in_reply_to_screen_name>
    //<geo/>
    //<contributors/>
    //</status>

    [DataContract]
    public class status
    {
        [DataMember]
        [Key]
        public string id { get; set; }
        //save date only as string for now as DateTimeOffset is not supported
        //public DateTimeOffset created_at_dt { get; set; }
        [DataMember]
        public string created_at
        {
            get; //{ return created_at_dt.ToString("ddd MMM dd HH:mm:ss zzz yyyy"); }
            set; //{ created_at_dt = DateTimeOffset.ParseExact(value, "ddd MMM dd HH:mm:ss zzz yyyy", CultureInfo.InvariantCulture);            }
        }


        [DataMember]
        public string text { get; set; }
        [DataMember]
        public string source { get; set; }
        [DataMember]
        public string truncated { get; set; }
        [DataMember]
        public string in_reply_to_status_id { get; set; }
        [DataMember]
        public string in_reply_to_user_id { get; set; }
        [DataMember]
        public string favorited { get; set; }
        [DataMember]
        public string in_reply_to_screen_name { get; set; }
        [DataMember]
        public user user { get; set; }
        [DataMember]
        public geo geo { get; set; }
        [DataMember]
        public string contributors { get; set; }
    }

    [DataContract]
    public class geo
    {
        [Key]
        public int geoId { get; set; }
        [DataMember]
        public string type { get; set; }
        [DataMember]
        public string[] coordinates { get; set; }
    }
}

DataStore.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;

namespace TwitterStreamClient
{
    class DataStore
    {
        static private TweetContext Db = null;

        private static TweetContext  getContext() {
            if(Db == null)
            {
                Db = new TweetContext();
            }
            return Db;
        }
        public static bool Add(status status)
        {
            TweetContext db = getContext();
            {
                db.status.Add(status);
                db.SaveChanges();
                return true;
            }
        }
    }
}

TweetContext.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;

namespace TwitterStreamClient
{
    class TweetContext : DbContext
    {
        public DbSet<status> status { get; set; }
        public DbSet<user> user { get; set; }

        static TweetContext()
        {
            // Database initialize
            Database.SetInitializer<TweetContext>(new DbInitializer());
            using (TweetContext db = new TweetContext())
                db.Database.Initialize(false);
        }

        class DbInitializer : DropCreateDatabaseAlways<TweetContext>
        {
        }
    }
}
  • 0
    Не могли бы вы поделиться настройкой таблиц состояния и пользователя, а также текущего кода, который вы используете, чтобы быть более точным, что вы делаете перед этим db.status.Add (status); db.SaveChanges ();
  • 0
    Я добавил фрагменты кода, которые вы просили! Я думаю, что главная проблема заключается в том, что я должен сказать EF, что пользователю необходимо обновить, если он уже существует. Но когда я пытаюсь использовать «Attach», он говорит мне, что «... другая сущность того же типа уже имеет то же значение первичного ключа». Но, насколько я вижу, я точно следую схеме, описанной здесь: msdn.microsoft.com/en-us/data/jj592676.aspx ( Присоединение существующего, но измененного объекта к контексту)
Показать ещё 5 комментариев
Теги:
entity-framework
entity-framework-6
twitter
twitter-streaming-api

2 ответа

0
Лучший ответ

Я нашел решение!

В версии 2 сверху мне просто нужно было изменить SingleOrDefault() на Any<user>() !

if(!db.user.Where<user>(u => u.id == status.user.id).Any<user>())
    db.user.Add(status.user);
else
{
    //db.user.Attach(status.user);
    db.Entry(status.user).State = EntityState.Modified;
}
    db.status.Add(status);
    db.SaveChanges();

Я думаю, проблема с получением пользователя с помощью SingleOrDefault() отслеживает пользователя с этим идентификатором, поэтому Attach() выдает исключение, потому что он уже отслеживает пользователя с этим идентификатором. Но когда я использую Any<user>() он просто проверяет наличие пользователя с этим ключом и не отслеживает его! Таким образом, возможно подключение пользователя.

0

У меня такая же проблема, когда я вставляю то, где я получаю ошибку. Я обновляю dbcontext, и моя проблема решена. Я не понимаю, но она отлично работает для меня.

just reinitialize your dbcontext  and check ....

Ещё вопросы

Сообщество Overcoder
Наверх
Меню