1 /* 2 * Entity - Entity is an object-relational mapping tool for the D programming language. Referring to the design idea of JPA. 3 * 4 * Copyright (C) 2015-2018 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: HuntLabs.cn 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.entity.EntityFieldManyToMany; 13 14 import hunt.entity; 15 import hunt.entity.EntityExpression; 16 import hunt.Exceptions; 17 18 import hunt.logging; 19 20 import std.format; 21 import std.variant; 22 23 24 class EntityFieldManyToMany(T : Object, F : Object = T,string MAPPEDBY = "") : EntityFieldObject!(T,F) { 25 26 27 private ManyToMany _mode; 28 private string _primaryKey; 29 private string _findString; 30 private T[][string] _decodeCache; 31 private EntityManager _em; 32 33 34 this(EntityManager manager, string fieldName, string primaryKey, string tableName, ManyToMany mode, F owner, bool isMainMapped ) { 35 // logDebug("ManyToMany(%s,%s) not main mapped ( %s , %s , %s , %s ,%s )".format(T.stringof,F.stringof,fieldName,primaryKey,tableName,mode,isMainMapped)); 36 _em = manager; 37 super(manager, fieldName, "", tableName, null, owner); 38 _isMainMapped = isMainMapped; 39 init(primaryKey, mode, owner); 40 } 41 42 this(EntityManager manager, string fieldName, string primaryKey, string tableName, ManyToMany mode, F owner, 43 bool isMainMapped ,JoinTable joinTable , JoinColumn jc ,InverseJoinColumn ijc ) { 44 // logDebug("ManyToMany(%s,%s) main mapped( %s , %s , %s , %s ,%s , %s , %s , %s )".format(T.stringof,F.stringof,fieldName,primaryKey,tableName,mode,isMainMapped,joinTable,jc,ijc)); 45 _em = manager; 46 super(manager, fieldName, "", tableName, null, owner); 47 _isMainMapped = isMainMapped; 48 _joinColumn = jc.name; 49 _inverseJoinColumn = ijc.name; 50 _joinTable = joinTable.name; 51 init(primaryKey, mode, owner); 52 } 53 54 private void init(string primaryKey, ManyToMany mode, F owner) { 55 _mode = mode; 56 _enableJoin = _mode.fetch == FetchType.EAGER; 57 _primaryKey = primaryKey; 58 static if(MAPPEDBY != "") 59 { 60 if(!_isMainMapped ) 61 { 62 _inverseJoinColumn = hunt.entity.utils.Common.getInverseJoinColumn!(T,MAPPEDBY).name; 63 _joinColumn = hunt.entity.utils.Common.getJoinColumn!(T,MAPPEDBY).name; 64 _joinTable = _em.getPrefix() ~ hunt.entity.utils.Common.getJoinTableName!(T,MAPPEDBY); 65 } 66 } 67 68 // logDebug("----(%s , %s ,%s )".format(_joinColumn,_inverseJoinColumn,_joinTable)); 69 70 initJoinData(); 71 initFindStr(); 72 } 73 74 private void initJoinData() { 75 _joinSqlData = new JoinSqlBuild(); 76 _joinSqlData.tableName = _joinTable; 77 if(_isMainMapped) 78 _joinSqlData.joinWhere = _entityInfo.getTableName() ~ "." ~ _entityInfo.getPrimaryKeyString ~ " = " ~ _joinTable ~ "." ~ _inverseJoinColumn; 79 else 80 _joinSqlData.joinWhere = _entityInfo.getTableName() ~ "." ~ _entityInfo.getPrimaryKeyString ~ " = " ~ _joinTable ~ "." ~ _joinColumn; 81 _joinSqlData.joinType = JoinType.LEFT; 82 // foreach(value; _entityInfo.getFields()) { 83 // _joinSqlData.columnNames ~= value.getSelectColumn(); 84 // } 85 // logDebug("many to many join sql : %s ".format(_joinSqlData)); 86 } 87 88 override public string getSelectColumn() { 89 return ""; 90 } 91 92 93 private void initFindStr() { 94 _findString = "SELECT "; 95 string[] el; 96 foreach(k,v; _entityInfo.getFields()) { 97 if (v.getSelectColumn() != "") 98 el ~= " "~v.getSelectColumn(); 99 } 100 foreach(k,v; el) { 101 _findString ~= v; 102 if (k != el.length -1) 103 _findString ~= ","; 104 } 105 _findString ~= " FROM "~_joinTable~" WHERE " ~ _joinTable ~"."~_joinColumn~" = "; 106 } 107 108 public string getPrimaryKey() {return _primaryKey;} 109 public ManyToMany getMode() {return _mode;} 110 111 override FetchType fetchType() { 112 return _mode.fetch; 113 } 114 115 public T[] deSerialize(Row[] rows, int startIndex, bool isFromManyToOne) { 116 T[] ret; 117 if (_mode.fetch == FetchType.LAZY) 118 return ret; 119 // logDebug("-----do do do ---"); 120 T singleRet; 121 long count = -1; 122 if (!isFromManyToOne) { 123 foreach(value; rows) { 124 singleRet = _entityInfo.deSerialize([value], count); 125 if (singleRet) 126 ret ~= Common.sampleCopy(singleRet); 127 } 128 } 129 else { 130 string joinValue = getJoinKeyValue(rows[startIndex]); 131 if (joinValue == "") 132 return ret; 133 T[] rets = getValueByJoinKeyValue(joinValue); 134 foreach(value; rets) { 135 ret ~= Common.sampleCopy(value); 136 } 137 } 138 return ret; 139 } 140 141 private string getJoinKeyValue(Row row) { 142 string name = EntityExpression.getColumnAsName(_primaryKey, getTableName()); 143 Variant v = row.getValue(name); 144 if(!v.hasValue()) { 145 version(HUNT_DEBUG) warningf("Can't find value for %s", name); 146 return null; 147 } 148 149 string value = v.toString(); 150 version(HUNT_ENTITY_DEBUG) tracef("A column: %s = %s", name, value); 151 return value; 152 } 153 154 private T[] getValueByJoinKeyValue(string key) { 155 if (key in _decodeCache) 156 return _decodeCache[key]; 157 158 T[] ret; 159 T singleRet; 160 auto stmt = _manager.getSession().prepare(_findString~key); 161 auto res = stmt.query(); 162 long count = -1; 163 foreach(value; res) { 164 singleRet = _entityInfo.deSerialize([value], count); 165 if (singleRet) 166 ret ~= singleRet; 167 } 168 _decodeCache[key] = ret; 169 return _decodeCache[key]; 170 } 171 172 public void setMode(ManyToMany mode) { 173 _mode = mode; 174 _enableJoin = _mode.fetch == FetchType.EAGER; 175 } 176 177 override LazyData getLazyData(Row row) { 178 logDebug("--- MappedBy : %s , row : %s ".format(_mode.mappedBy, row)); 179 string name = EntityExpression.getColumnAsName(_primaryKey, getTableName()); 180 Variant v = row.getValue(name); 181 if(!v.hasValue()) { 182 warningf("Can't find value for %s", name); 183 return null; 184 } 185 186 string value = v.toString(); 187 version(HUNT_ENTITY_DEBUG) tracef("A column: %s = %s", name, value); 188 LazyData ret = new LazyData(_mode.mappedBy, value); 189 return ret; 190 } 191 192 193 194 }