[解決済み] エンティティを永続化しようとしたときに、同じ識別子値を持つ別のオブジェクトがすでにセッションに関連付けられました。
質問
ちょっとした問題があり、解決方法がわかりません。助けていただけませんか? エンティティを永続化しようとすると、次のような例外が発生します。
12:47:39,398 ERROR [org.black.dmitriy.entityHome.ScheduleHome] (http--127.0.0.1-8080-1) javax.persistence.EntityExistsException: a different object with the same identifier value was already associated with the session: [org.black.dmitriy.entity.Schedule#1]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1333) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1289) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1295) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:859) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.seam.persistence.EntityManagerInvocationHandler.invoke(EntityManagerInvocationHandler.java:46) [jboss-seam.jar:2.3.0.Final]
at $Proxy81.persist(Unknown Source) at org.jboss.seam.framework.EntityHome.persist(EntityHome.java:84) [jboss-seam.jar:2.3.0.Final]
at org.black.dmitriy.entityHome.ConversationHome.tryPersist(ConversationHome.java:147) [ejb.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.seam.util.Reflections.invoke(Reflections.java:22) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:32) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:28) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.core.ConversationInterceptor.aroundInvoke(ConversationInterceptor.java:65) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.TransactionInterceptor$1.work(TransactionInterceptor.java:97) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.util.Work.workInTransaction(Work.java:61) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:91) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:44) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:186) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:104) [jboss-seam.jar:2.3.0.Final]
at org.black.dmitriy.entityHome.ScheduleHome_$$_javassist_seam_8.tryPersist(ScheduleHome_$$_javassist_seam_8.java) [ejb.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:335) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:348) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.parser.AstPropertySuffix.invoke(AstPropertySuffix.java:58) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.parser.AstValue.invoke(AstValue.java:96) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.component.UICommand.broadcast(UICommand.java:315) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) [jboss-seam.jar:2.3.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:397) [jbossweb-7.0.13.Final.jar:]
at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_04]
私はseam2.3、hibernateを使用しています。私のimport.sqlファイルに1つのinsert文があります。
INSERT INTO Schedules (id, name, dayCount, lessonCount, firstTermSize, secondTermSize, subgroupSize) VALUES(1, '2012/2013', 5, 8, 9, 9, 18)
これは、テーブルSchedulesにエンティティを1つ挿入するものです。
次に、EntityHomeを使用して、新しいScheduleエンティティをWebページに投げます。
@Name("scheduleHome")
@Scope(ScopeType.CONVERSATION)
public class ScheduleHome extends ConversationHome<Schedule> {
private static final long serialVersionUID = 1L;
public ScheduleHome() {
}
@Override
protected boolean isUnique() {
Schedule schedule = getInstance();
Schedule foundSchedule = ScheduleDAO.instance().getByName(schedule.getName());
if ((foundSchedule != null) && (!foundSchedule.equals(schedule))) {
showExistsErrorMessage(getInstance().getName());
return false;
}
return true;
}
@Override
protected Schedule createInstance() {
return new Schedule();
}
@Override
public String getEditOutcome() {
return "scheduleEdit";
}
@Override
protected void prepareEntityForSaving() {
}
}
とスーパークラス
public abstract class ConversationHome<T> extends EntityHome<T> {
private static final long serialVersionUID = 1L;
private String parentView;
public boolean isParentViewExists() {
return parentView != null && parentView.length() > 0;
}
public void setParentView(String parentView) {
this.parentView = parentView;
}
public String getParentView() {
return parentView;
}
public abstract String getEditOutcome();
protected abstract void prepareEntityForSaving();
protected abstract boolean isUnique();
@Override
@Create
public void create() {
create(false);
}
protected void create(boolean createNestedConversation) {
Conversation conversation = Conversation.instance();
if (!createNestedConversation && conversation.isLongRunning()) {
getLog().debug("conversation already started, nested will not create(isLongRunning = #0, isNested = #1)", conversation.isLongRunning(), conversation.isNested());
} else {
conversation.begin(false, conversation.isLongRunning());
conversation.changeFlushMode(FlushModeType.MANUAL);
getLog().debug("create(isLongRunning = #0, isNested = #1, id = #2)", conversation.isLongRunning(), conversation.isNested(), conversation.getId());
}
super.create();
}
private boolean init(Long id) {
FacesContext context = FacesContext.getCurrentInstance();
setParentView(Pages.getViewId(context));
if (id != null) {
setId(id);
try {
getInstance();
getLog().debug("instance initialized #0", getInstance());
} catch (EntityNotFoundException e) {
getLog().error(e);
return false;
}
}
return true;
}
public String startEdit(Long id) {
getLog().debug("start editing #0", id);
if (init(id)) {
return getEditOutcome();
} else {
return cancel();
}
}
public String cancel() {
if (isManaged()) {
getEntityManager().refresh(getInstance());
}
return returnToParent();
}
@End
protected String returnToParent() {
if (isParentViewExists()) {
Conversation conversation = Conversation.instance();
getLog().debug("end conversation(id = #0, isLongRunning = #1, isNested = #2)",
conversation.getId(), conversation.isLongRunning(), conversation.isNested());
conversation.end(true);
return getParentView();
} else {
clearInstance();
return null;
}
}
public String tryPersist() {
if (isUnique()) {
try {
prepareEntityForSaving();
String outcome = persist();
if (!"failed".equals(outcome)) {
return returnToParent();
}
} catch (Exception e) {
getLog().error(getInstance(), e);
showSaveErrorMessage(e);
}
}
return "failed";
}
}
そして、それを永続化しようとすると、この例外が発生します。
Save error with message: a different object with the same identifier value was already associated with the session.このメッセージは、同じ識別子値を持つ別のオブジェクトがすでにセッションに関連付けされていることを意味します。[org.black.dmitriy.entity.Schedule#1] というメッセージが表示されました。
hibernate は id プロパティを 1 に設定したようですが、私はすでにエンティティに
id = 1
というのも、import.sqlを投げて手動で作成したからです。
これが私のスケジュール・エンティティです。
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
@Entity
@Table(name = "Schedules")
public class Schedule {
@Id
@GeneratedValue
@Column(name = "id", nullable = false)
private Long id;
@NotNull
@Column(name = "name", nullable = false, length = 40)
private String name;
@Column(name = "dayCount")
private int dayCount = 5;
@Column(name = "lessonCount")
private int lessonCount = 8;
@Column(name = "firstTermSize")
private int firstTermSize = 9;
@Column(name = "secondTermSize")
private int secondTermSize = 9;
@Column(name = "subgroupSize")
private int subgroupSize = 18;
@OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, targetEntity = Faculty.class)
private List<Faculty> faculties = new ArrayList<>();
@OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, targetEntity = Building.class)
private List<Building> buildings = new ArrayList<>();
public Schedule() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDayCount() {
return dayCount;
}
public void setDayCount(int dayCount) {
this.dayCount = dayCount;
}
public int getLessonCount() {
return lessonCount;
}
public void setLessonCount(int lessonCount) {
this.lessonCount = lessonCount;
}
public int getFirstTermSize() {
return firstTermSize;
}
public void setFirstTermSize(int firstTermSize) {
this.firstTermSize = firstTermSize;
}
public int getSecondTermSize() {
return secondTermSize;
}
public void setSecondTermSize(int secondTermSize) {
this.secondTermSize = secondTermSize;
}
public int getSubgroupSize() {
return subgroupSize;
}
public void setSubgroupSize(int subgroupSize) {
this.subgroupSize = subgroupSize;
}
public List<Faculty> getFaculties() {
return faculties;
}
public void setFaculties(List<Faculty> faculties) {
this.faculties = faculties;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Schedule)) {
return false;
}
Schedule other = (Schedule) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
@Override
public String toString() {
return this.name;
}
}
idプロパティに@GeneratedValueアノテーションがあるので、hibernateが自分でidを生成して、データベースにid = 1のエンティティがあることを知り、新しいエンティティにid = 2を設定するはずだと思うのです。しかし、Hibernateは新しいエンティティのidを1に設定します。 私を助けていただけますか?
どうすればいいですか?
問題は、Hibernateがどのように
id
データベースに保存する前にオブジェクトに1を代入すると、同じIDの行がすでにデータベースに存在することがわかり、例外が発生します。この問題のシンプルで自然な解決策は、ハイバーネートを制限して、オブジェクトに
1
をidとして、関連するクラス(あなたの場合)のどのオブジェクトにも適用できます。
mySqlの解決策。
mySql を使用している場合、手動でテーブルを作成し、自動インクリメントを設定することができます。
CREATE TABLE IF NOT EXISTS `testTable` (
`id` number(11) NOT NULL AUTO_INCREMENT,
...,
...,
...,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2; //assigning id by hibernate, will start from 2.
そして、ドメインクラスには、以下のようなidアノテーションをつけることができます。
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
public long getId() {
....
}
GenerationType.AUTO
を設定すると、デフォルトでは mySql の自動インクリメントが使用されます。
AUTO_INCREMENT=2
ハイバーネートは、id を
2
(そのため
1
はスキップされます)。
Oracleの解決策。
Oracleの場合は、hibernateがquot;sequence"を使用するように制限し、シーケンスの始点を任意に設定すれば、同じことが可能です。シーケンスの始点は
2
で増加し
1
のようにします。
create sequence idSequence
start with 2
increment by 1
maxvalue 9999999999999;
そして、ドメインクラスのオブジェクトのIDを生成するために使用するシーケンスを、以下のように指定することができます。
@Id
@SequenceGenerator(name = "idGeneratorSeq", sequenceName = "idSequence")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "idGeneratorSeq")
@Column(name = "ID")
public long getId() {
....
}
そして、あなたの問題は解決されました。
関連
-
[解決済み】Athena: スケールファクターでリソースを使い果たすクエリ
-
[解決済み】sys.dm_exec_sql_textはどのように機能するのでしょうか?
-
[解決済み] INSERT ステートメントが FOREIGN KEY 制約と競合する - SQL Server
-
[解決済み] Presto SQL ピボッティング(言葉は悪いですが)データ
-
[解決済み] ORA-00918: 列があいまいに定義されています」を解決する方法
-
[解決済み] 集計を行わずに行から列へピボット移動する
-
[解決済み] PostgreSQL - json 型の等値演算子を識別できませんでした。
-
[解決済み] SQLでchar値をmoneyに変換できない
-
[解決済み] ORA-01821: ISO 8601 のローカルタイム付き日付のフォーマットが認識されないエラー
-
[解決済み] マルチパート識別子をバインドできなかった
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] テーブルのFROM句の項目がない [終了しました] 。
-
[解決済み】オペランド型の衝突:intはdateと互換性がない + INSERT文はFOREIGN KEY制約と衝突した
-
[解決済み] varchar 値 'simple, ' をデータ型 int に変換する際に変換に失敗しました。
-
[解決済み】一括読み込みデータ変換エラー(指定されたコードページに対して型の不一致または無効な文字)1行目4列目(年)について)
-
[解決済み】SQL Server サブクエリが1つ以上の値を返しました。サブクエリが =, !=, <, <= , >, >= に続く場合、これは許可されません。
-
[解決済み] エラー (ORA-00923: 期待された場所に FROM キーワードが見つかりませんでした)
-
[解決済み] エラー: 名前解析スクリプトで正しい関数に渡された長さのパラメーターが無効です。
-
[解決済み] ORA-01735: 無効な ALTER TABLE オプション - ヒキガエル
-
[解決済み] リンクされたサーバーの NULL に対して OLE DB プロバイダー Microsoft.Jet.OLEDB.4.0 のインスタンスを作成できません。
-
[解決済み] SQL Server - INNER JOIN WITH DISTINCT